blob: 8c58001c76d49afa1c87aa1f0be88be5cb2152e0 [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-Cohen958b20e2011-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 Peller536129c2011-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 Pellerba8447f2011-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 Pellerba8447f2011-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 Pellerba8447f2011-10-10 10:13:00 +0200453 wl12xx_for_each_wlvif_sta(wl, wlvif) {
454 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
455 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300456
Eliad Pellerba8447f2011-10-10 10:13:00 +0200457 ret = wl1271_ps_elp_wakeup(wl);
458 if (ret < 0)
459 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300460
Eliad Pellerba8447f2011-10-10 10:13:00 +0200461 wl1271_check_operstate(wl, wlvif, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300462
Eliad Pellerba8447f2011-10-10 10:13:00 +0200463 wl1271_ps_elp_sleep(wl);
464 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300465out:
466 mutex_unlock(&wl->mutex);
467
468 return NOTIFY_OK;
469}
470
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100471static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200472 struct regulatory_request *request)
473{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100474 struct ieee80211_supported_band *band;
475 struct ieee80211_channel *ch;
476 int i;
477
478 band = wiphy->bands[IEEE80211_BAND_5GHZ];
479 for (i = 0; i < band->n_channels; i++) {
480 ch = &band->channels[i];
481 if (ch->flags & IEEE80211_CHAN_DISABLED)
482 continue;
483
484 if (ch->flags & IEEE80211_CHAN_RADAR)
485 ch->flags |= IEEE80211_CHAN_NO_IBSS |
486 IEEE80211_CHAN_PASSIVE_SCAN;
487
488 }
489
490 return 0;
491}
492
Eliad Peller9eb599e2011-10-10 10:12:59 +0200493static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
494 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300495{
496 int ret = 0;
497
498 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200499 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300500 if (ret < 0)
501 goto out;
502
503 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200504 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300505 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200506 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300507out:
508 return ret;
509}
510
511/*
512 * this function is being called when the rx_streaming interval
513 * has beed changed or rx_streaming should be disabled
514 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200515int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300516{
517 int ret = 0;
518 int period = wl->conf.rx_streaming.interval;
519
520 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200521 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300522 goto out;
523
524 /* reconfigure/disable according to new streaming_period */
525 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200526 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300527 (wl->conf.rx_streaming.always ||
528 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200529 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300530 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200531 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300532 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200533 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300534 }
535out:
536 return ret;
537}
538
539static void wl1271_rx_streaming_enable_work(struct work_struct *work)
540{
541 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200542 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
543 rx_streaming_enable_work);
544 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300545
546 mutex_lock(&wl->mutex);
547
Eliad Peller0744bdb2011-10-10 10:13:05 +0200548 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200549 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300550 (!wl->conf.rx_streaming.always &&
551 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
552 goto out;
553
554 if (!wl->conf.rx_streaming.interval)
555 goto out;
556
557 ret = wl1271_ps_elp_wakeup(wl);
558 if (ret < 0)
559 goto out;
560
Eliad Peller9eb599e2011-10-10 10:12:59 +0200561 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300562 if (ret < 0)
563 goto out_sleep;
564
565 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200566 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300567 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
568
569out_sleep:
570 wl1271_ps_elp_sleep(wl);
571out:
572 mutex_unlock(&wl->mutex);
573}
574
575static void wl1271_rx_streaming_disable_work(struct work_struct *work)
576{
577 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200578 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
579 rx_streaming_disable_work);
580 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300581
582 mutex_lock(&wl->mutex);
583
Eliad Peller0744bdb2011-10-10 10:13:05 +0200584 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300585 goto out;
586
587 ret = wl1271_ps_elp_wakeup(wl);
588 if (ret < 0)
589 goto out;
590
Eliad Peller9eb599e2011-10-10 10:12:59 +0200591 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300592 if (ret)
593 goto out_sleep;
594
595out_sleep:
596 wl1271_ps_elp_sleep(wl);
597out:
598 mutex_unlock(&wl->mutex);
599}
600
601static void wl1271_rx_streaming_timer(unsigned long data)
602{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200603 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
604 struct wl1271 *wl = wlvif->wl;
605 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300606}
607
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300608static void wl1271_conf_init(struct wl1271 *wl)
609{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300610
611 /*
612 * This function applies the default configuration to the driver. This
613 * function is invoked upon driver load (spi probe.)
614 *
615 * The configuration is stored in a run-time structure in order to
616 * facilitate for run-time adjustment of any of the parameters. Making
617 * changes to the configuration structure will apply the new values on
618 * the next interface up (wl1271_op_start.)
619 */
620
621 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300622 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300623
Ido Yariv95dac04f2011-06-06 14:57:06 +0300624 /* Adjust settings according to optional module parameters */
625 if (fwlog_param) {
626 if (!strcmp(fwlog_param, "continuous")) {
627 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
628 } else if (!strcmp(fwlog_param, "ondemand")) {
629 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
630 } else if (!strcmp(fwlog_param, "dbgpins")) {
631 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
632 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
633 } else if (!strcmp(fwlog_param, "disable")) {
634 wl->conf.fwlog.mem_blocks = 0;
635 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
636 } else {
637 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
638 }
639 }
640}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300641
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300642static int wl1271_plt_init(struct wl1271 *wl)
643{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200644 struct conf_tx_ac_category *conf_ac;
645 struct conf_tx_tid *conf_tid;
646 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300647
Shahar Levi49d750ca2011-03-06 16:32:09 +0200648 if (wl->chip.id == CHIP_ID_1283_PG20)
649 ret = wl128x_cmd_general_parms(wl);
650 else
651 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200652 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200653 return ret;
654
Shahar Levi49d750ca2011-03-06 16:32:09 +0200655 if (wl->chip.id == CHIP_ID_1283_PG20)
656 ret = wl128x_cmd_radio_parms(wl);
657 else
658 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200659 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200660 return ret;
661
Shahar Levi49d750ca2011-03-06 16:32:09 +0200662 if (wl->chip.id != CHIP_ID_1283_PG20) {
663 ret = wl1271_cmd_ext_radio_parms(wl);
664 if (ret < 0)
665 return ret;
666 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200667 if (ret < 0)
668 return ret;
669
Shahar Levi48a61472011-03-06 16:32:08 +0200670 /* Chip-specific initializations */
671 ret = wl1271_chip_specific_init(wl);
672 if (ret < 0)
673 return ret;
674
Eliad Peller92c77c72011-10-05 11:55:40 +0200675 ret = wl1271_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200676 if (ret < 0)
677 return ret;
678
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679 ret = wl1271_acx_init_mem_config(wl);
680 if (ret < 0)
681 return ret;
682
Luciano Coelho12419cc2010-02-18 13:25:44 +0200683 /* PHY layer config */
684 ret = wl1271_init_phy_config(wl);
685 if (ret < 0)
686 goto out_free_memmap;
687
688 ret = wl1271_acx_dco_itrim_params(wl);
689 if (ret < 0)
690 goto out_free_memmap;
691
692 /* Initialize connection monitoring thresholds */
Eliad Peller0603d892011-10-05 11:55:51 +0200693 ret = wl1271_acx_conn_monit_params(wl, NULL, false); /* TODO: fix */
Luciano Coelho12419cc2010-02-18 13:25:44 +0200694 if (ret < 0)
695 goto out_free_memmap;
696
697 /* Bluetooth WLAN coexistence */
698 ret = wl1271_init_pta(wl);
699 if (ret < 0)
700 goto out_free_memmap;
701
Shahar Leviff868432011-04-11 15:41:46 +0300702 /* FM WLAN coexistence */
703 ret = wl1271_acx_fm_coex(wl);
704 if (ret < 0)
705 goto out_free_memmap;
706
Luciano Coelho12419cc2010-02-18 13:25:44 +0200707 /* Energy detection */
708 ret = wl1271_init_energy_detection(wl);
709 if (ret < 0)
710 goto out_free_memmap;
711
Eliad Peller7f0979882011-08-14 13:17:06 +0300712 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600713 if (ret < 0)
714 goto out_free_memmap;
715
Luciano Coelho12419cc2010-02-18 13:25:44 +0200716 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100717 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200718 if (ret < 0)
719 goto out_free_memmap;
720
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200721 /* Default TID/AC configuration */
722 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200723 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200724 conf_ac = &wl->conf.tx.ac_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200725 /* TODO: fix */
726 ret = wl1271_acx_ac_cfg(wl, NULL, conf_ac->ac, conf_ac->cw_min,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200727 conf_ac->cw_max, conf_ac->aifsn,
728 conf_ac->tx_op_limit);
729 if (ret < 0)
730 goto out_free_memmap;
731
Luciano Coelho12419cc2010-02-18 13:25:44 +0200732 conf_tid = &wl->conf.tx.tid_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200733 /* TODO: fix */
734 ret = wl1271_acx_tid_cfg(wl, NULL, conf_tid->queue_id,
Luciano Coelho12419cc2010-02-18 13:25:44 +0200735 conf_tid->channel_type,
736 conf_tid->tsid,
737 conf_tid->ps_scheme,
738 conf_tid->ack_policy,
739 conf_tid->apsd_conf[0],
740 conf_tid->apsd_conf[1]);
741 if (ret < 0)
742 goto out_free_memmap;
743 }
744
Luciano Coelho12419cc2010-02-18 13:25:44 +0200745 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200746 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300747 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200748 goto out_free_memmap;
749
750 /* Configure for CAM power saving (ie. always active) */
751 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
752 if (ret < 0)
753 goto out_free_memmap;
754
755 /* configure PM */
756 ret = wl1271_acx_pm_config(wl);
757 if (ret < 0)
758 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300759
760 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200761
762 out_free_memmap:
763 kfree(wl->target_mem_map);
764 wl->target_mem_map = NULL;
765
766 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767}
768
Eliad Peller6e8cd332011-10-10 10:13:13 +0200769static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
770 struct wl12xx_vif *wlvif,
771 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200772{
Arik Nemtsovda032092011-08-25 12:43:15 +0300773 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200774
Arik Nemtsovb622d992011-02-23 00:22:31 +0200775 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300776 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200777
778 /*
779 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300780 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200781 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300782 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200783 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200784
Arik Nemtsovda032092011-08-25 12:43:15 +0300785 /*
786 * Start high-level PS if the STA is asleep with enough blocks in FW.
787 * Make an exception if this is the only connected station. In this
788 * case FW-memory congestion is not a problem.
789 */
790 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200791 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200792}
793
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300794static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200795 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300796 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200797{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200798 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200799 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300800 u8 hlid, cnt;
801
802 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200803
804 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
805 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
806 wl1271_debug(DEBUG_PSM,
807 "link ps prev 0x%x cur 0x%x changed 0x%x",
808 wl->ap_fw_ps_map, cur_fw_ps_map,
809 wl->ap_fw_ps_map ^ cur_fw_ps_map);
810
811 wl->ap_fw_ps_map = cur_fw_ps_map;
812 }
813
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200814 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
815 lnk = &wl->links[hlid];
816 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200817
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200818 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
819 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200820
Eliad Peller6e8cd332011-10-10 10:13:13 +0200821 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
822 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200823 }
824}
825
Eliad Peller4d56ad92011-08-14 13:17:05 +0300826static void wl12xx_fw_status(struct wl1271 *wl,
827 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200829 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200830 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200831 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300832 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300833 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834
Eliad Peller4d56ad92011-08-14 13:17:05 +0300835 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200836
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300837 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
838 "drv_rx_counter = %d, tx_results_counter = %d)",
839 status->intr,
840 status->fw_rx_counter,
841 status->drv_rx_counter,
842 status->tx_results_counter);
843
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300844 for (i = 0; i < NUM_TX_QUEUES; i++) {
845 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300846 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300847 (status->tx_released_pkts[i] -
848 wl->tx_pkts_freed[i]) & 0xff;
849
850 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
851 }
852
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300853 /* prevent wrap-around in total blocks counter */
854 if (likely(wl->tx_blocks_freed <=
855 le32_to_cpu(status->total_released_blks)))
856 freed_blocks = le32_to_cpu(status->total_released_blks) -
857 wl->tx_blocks_freed;
858 else
859 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
860 le32_to_cpu(status->total_released_blks);
861
Eliad Peller4d56ad92011-08-14 13:17:05 +0300862 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200863
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300864 wl->tx_allocated_blocks -= freed_blocks;
865
Eliad Peller4d56ad92011-08-14 13:17:05 +0300866 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200867
Eliad Peller4d56ad92011-08-14 13:17:05 +0300868 /*
869 * The FW might change the total number of TX memblocks before
870 * we get a notification about blocks being released. Thus, the
871 * available blocks calculation might yield a temporary result
872 * which is lower than the actual available blocks. Keeping in
873 * mind that only blocks that were allocated can be moved from
874 * TX to RX, tx_blocks_available should never decrease here.
875 */
876 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
877 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878
Ido Yariva5225502010-10-12 14:49:10 +0200879 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200880 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200881 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300882
Eliad Peller4d56ad92011-08-14 13:17:05 +0300883 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200884 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200885 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200886 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300887
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300888 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200889 getnstimeofday(&ts);
890 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
891 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300892}
893
Ido Yariva6208652011-03-01 15:14:41 +0200894static void wl1271_flush_deferred_work(struct wl1271 *wl)
895{
896 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200897
Ido Yariva6208652011-03-01 15:14:41 +0200898 /* Pass all received frames to the network stack */
899 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
900 ieee80211_rx_ni(wl->hw, skb);
901
902 /* Return sent skbs to the network stack */
903 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300904 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200905}
906
907static void wl1271_netstack_work(struct work_struct *work)
908{
909 struct wl1271 *wl =
910 container_of(work, struct wl1271, netstack_work);
911
912 do {
913 wl1271_flush_deferred_work(wl);
914 } while (skb_queue_len(&wl->deferred_rx_queue));
915}
916
917#define WL1271_IRQ_MAX_LOOPS 256
918
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300919static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300920{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300921 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300922 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200923 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200924 struct wl1271 *wl = (struct wl1271 *)cookie;
925 bool done = false;
926 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200927 unsigned long flags;
928
929 /* TX might be handled here, avoid redundant work */
930 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
931 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932
Ido Yariv341b7cd2011-03-31 10:07:01 +0200933 /*
934 * In case edge triggered interrupt must be used, we cannot iterate
935 * more than once without introducing race conditions with the hardirq.
936 */
937 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
938 loopcount = 1;
939
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300940 mutex_lock(&wl->mutex);
941
942 wl1271_debug(DEBUG_IRQ, "IRQ work");
943
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200944 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945 goto out;
946
Ido Yariva6208652011-03-01 15:14:41 +0200947 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948 if (ret < 0)
949 goto out;
950
Ido Yariva6208652011-03-01 15:14:41 +0200951 while (!done && loopcount--) {
952 /*
953 * In order to avoid a race with the hardirq, clear the flag
954 * before acknowledging the chip. Since the mutex is held,
955 * wl1271_ps_elp_wakeup cannot be called concurrently.
956 */
957 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
958 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200959
Eliad Peller4d56ad92011-08-14 13:17:05 +0300960 wl12xx_fw_status(wl, wl->fw_status);
961 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200962 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200963 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200964 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200965 continue;
966 }
967
Eliad Pellerccc83b02010-10-27 14:09:57 +0200968 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
969 wl1271_error("watchdog interrupt received! "
970 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300971 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200972
973 /* restarting the chip. ignore any other interrupt. */
974 goto out;
975 }
976
Ido Yariva6208652011-03-01 15:14:41 +0200977 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200978 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
979
Eliad Peller4d56ad92011-08-14 13:17:05 +0300980 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200981
Ido Yariva5225502010-10-12 14:49:10 +0200982 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200983 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200984 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300985 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200986 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200987 /*
988 * In order to avoid starvation of the TX path,
989 * call the work function directly.
990 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200991 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200992 } else {
993 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200994 }
995
Ido Yariv8aad2462011-03-01 15:14:38 +0200996 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300997 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200998 (wl->tx_results_count & 0xff))
999 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001000
1001 /* Make sure the deferred queues don't get too long */
1002 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1003 skb_queue_len(&wl->deferred_rx_queue);
1004 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1005 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001006 }
1007
1008 if (intr & WL1271_ACX_INTR_EVENT_A) {
1009 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1010 wl1271_event_handle(wl, 0);
1011 }
1012
1013 if (intr & WL1271_ACX_INTR_EVENT_B) {
1014 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1015 wl1271_event_handle(wl, 1);
1016 }
1017
1018 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1019 wl1271_debug(DEBUG_IRQ,
1020 "WL1271_ACX_INTR_INIT_COMPLETE");
1021
1022 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1023 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024 }
1025
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026 wl1271_ps_elp_sleep(wl);
1027
1028out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001029 spin_lock_irqsave(&wl->wl_lock, flags);
1030 /* In case TX was not handled here, queue TX work */
1031 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1032 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001033 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001034 ieee80211_queue_work(wl->hw, &wl->tx_work);
1035 spin_unlock_irqrestore(&wl->wl_lock, flags);
1036
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001038
1039 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040}
1041
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042static int wl1271_fetch_firmware(struct wl1271 *wl)
1043{
1044 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001045 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046 int ret;
1047
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001048 if (wl->chip.id == CHIP_ID_1283_PG20)
1049 fw_name = WL128X_FW_NAME;
1050 else
1051 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001052
1053 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1054
Felipe Balbia390e852011-10-06 10:07:44 +03001055 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056
1057 if (ret < 0) {
1058 wl1271_error("could not get firmware: %d", ret);
1059 return ret;
1060 }
1061
1062 if (fw->size % 4) {
1063 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1064 fw->size);
1065 ret = -EILSEQ;
1066 goto out;
1067 }
1068
Arik Nemtsov166d5042010-10-16 21:44:57 +02001069 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001070 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001071 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001072
1073 if (!wl->fw) {
1074 wl1271_error("could not allocate memory for the firmware");
1075 ret = -ENOMEM;
1076 goto out;
1077 }
1078
1079 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080 ret = 0;
1081
1082out:
1083 release_firmware(fw);
1084
1085 return ret;
1086}
1087
1088static int wl1271_fetch_nvs(struct wl1271 *wl)
1089{
1090 const struct firmware *fw;
1091 int ret;
1092
Felipe Balbia390e852011-10-06 10:07:44 +03001093 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001094
1095 if (ret < 0) {
1096 wl1271_error("could not get nvs file: %d", ret);
1097 return ret;
1098 }
1099
Shahar Levibc765bf2011-03-06 16:32:10 +02001100 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001101
1102 if (!wl->nvs) {
1103 wl1271_error("could not allocate memory for the nvs file");
1104 ret = -ENOMEM;
1105 goto out;
1106 }
1107
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001108 wl->nvs_len = fw->size;
1109
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001110out:
1111 release_firmware(fw);
1112
1113 return ret;
1114}
1115
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001116void wl12xx_queue_recovery_work(struct wl1271 *wl)
1117{
1118 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1119 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1120}
1121
Ido Yariv95dac04f2011-06-06 14:57:06 +03001122size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1123{
1124 size_t len = 0;
1125
1126 /* The FW log is a length-value list, find where the log end */
1127 while (len < maxlen) {
1128 if (memblock[len] == 0)
1129 break;
1130 if (len + memblock[len] + 1 > maxlen)
1131 break;
1132 len += memblock[len] + 1;
1133 }
1134
1135 /* Make sure we have enough room */
1136 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1137
1138 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1139 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1140 wl->fwlog_size += len;
1141
1142 return len;
1143}
1144
1145static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1146{
1147 u32 addr;
1148 u32 first_addr;
1149 u8 *block;
1150
1151 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1152 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1153 (wl->conf.fwlog.mem_blocks == 0))
1154 return;
1155
1156 wl1271_info("Reading FW panic log");
1157
1158 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1159 if (!block)
1160 return;
1161
1162 /*
1163 * Make sure the chip is awake and the logger isn't active.
1164 * This might fail if the firmware hanged.
1165 */
1166 if (!wl1271_ps_elp_wakeup(wl))
1167 wl12xx_cmd_stop_fwlog(wl);
1168
1169 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001170 wl12xx_fw_status(wl, wl->fw_status);
1171 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001172 if (!first_addr)
1173 goto out;
1174
1175 /* Traverse the memory blocks linked list */
1176 addr = first_addr;
1177 do {
1178 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1179 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1180 false);
1181
1182 /*
1183 * Memory blocks are linked to one another. The first 4 bytes
1184 * of each memory block hold the hardware address of the next
1185 * one. The last memory block points to the first one.
1186 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001187 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001188 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1189 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1190 break;
1191 } while (addr && (addr != first_addr));
1192
1193 wake_up_interruptible(&wl->fwlog_waitq);
1194
1195out:
1196 kfree(block);
1197}
1198
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001199static void wl1271_recovery_work(struct work_struct *work)
1200{
1201 struct wl1271 *wl =
1202 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001203 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001204 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001205
1206 mutex_lock(&wl->mutex);
1207
1208 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001209 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001210
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001211 /* Avoid a recursive recovery */
1212 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1213
Ido Yariv95dac04f2011-06-06 14:57:06 +03001214 wl12xx_read_fwlog_panic(wl);
1215
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001216 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1217 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001218
Eliad Peller2a5bff02011-08-25 18:10:59 +03001219 BUG_ON(bug_on_recovery);
1220
Oz Krakowskib992c682011-06-26 10:36:02 +03001221 /*
1222 * Advance security sequence number to overcome potential progress
1223 * in the firmware during recovery. This doens't hurt if the network is
1224 * not encrypted.
1225 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001226 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001227 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001228 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001229 wlvif->tx_security_seq +=
1230 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1231 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001232
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001233 /* Prevent spurious TX during FW restart */
1234 ieee80211_stop_queues(wl->hw);
1235
Luciano Coelho33c2c062011-05-10 14:46:02 +03001236 if (wl->sched_scanning) {
1237 ieee80211_sched_scan_stopped(wl->hw);
1238 wl->sched_scanning = false;
1239 }
1240
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001241 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001242 while (!list_empty(&wl->wlvif_list)) {
1243 wlvif = list_first_entry(&wl->wlvif_list,
1244 struct wl12xx_vif, list);
1245 vif = wl12xx_wlvif_to_vif(wlvif);
1246 __wl1271_op_remove_interface(wl, vif, false);
1247 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001248 mutex_unlock(&wl->mutex);
1249 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001250
1251 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1252
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001253 ieee80211_restart_hw(wl->hw);
1254
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001255 /*
1256 * Its safe to enable TX now - the queues are stopped after a request
1257 * to restart the HW.
1258 */
1259 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001260 return;
1261out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001262 mutex_unlock(&wl->mutex);
1263}
1264
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001265static void wl1271_fw_wakeup(struct wl1271 *wl)
1266{
1267 u32 elp_reg;
1268
1269 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001270 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001271}
1272
1273static int wl1271_setup(struct wl1271 *wl)
1274{
1275 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1276 if (!wl->fw_status)
1277 return -ENOMEM;
1278
1279 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1280 if (!wl->tx_res_if) {
1281 kfree(wl->fw_status);
1282 return -ENOMEM;
1283 }
1284
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 return 0;
1286}
1287
1288static int wl1271_chip_wakeup(struct wl1271 *wl)
1289{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001290 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291 int ret = 0;
1292
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001293 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001294 ret = wl1271_power_on(wl);
1295 if (ret < 0)
1296 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001297 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001298 wl1271_io_reset(wl);
1299 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001300
1301 /* We don't need a real memory partition here, because we only want
1302 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001303 memset(&partition, 0, sizeof(partition));
1304 partition.reg.start = REGISTERS_BASE;
1305 partition.reg.size = REGISTERS_DOWN_SIZE;
1306 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001307
1308 /* ELP module wake up */
1309 wl1271_fw_wakeup(wl);
1310
1311 /* whal_FwCtrl_BootSm() */
1312
1313 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001314 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001316 /*
1317 * For wl127x based devices we could use the default block
1318 * size (512 bytes), but due to a bug in the sdio driver, we
1319 * need to set it explicitly after the chip is powered on. To
1320 * simplify the code and since the performance impact is
1321 * negligible, we use the same block size for all different
1322 * chip types.
1323 */
1324 if (!wl1271_set_block_size(wl))
1325 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001326
1327 switch (wl->chip.id) {
1328 case CHIP_ID_1271_PG10:
1329 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1330 wl->chip.id);
1331
1332 ret = wl1271_setup(wl);
1333 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001334 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001335 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001336 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001337
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001338 case CHIP_ID_1271_PG20:
1339 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1340 wl->chip.id);
1341
1342 ret = wl1271_setup(wl);
1343 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001344 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001345 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001346 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001347
Shahar Levi0830cee2011-03-06 16:32:20 +02001348 case CHIP_ID_1283_PG20:
1349 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1350 wl->chip.id);
1351
1352 ret = wl1271_setup(wl);
1353 if (ret < 0)
1354 goto out;
1355 break;
1356 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001358 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001360 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001361 }
1362
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001363 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364 ret = wl1271_fetch_firmware(wl);
1365 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001366 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367 }
1368
1369 /* No NVS from netlink, try to get it from the filesystem */
1370 if (wl->nvs == NULL) {
1371 ret = wl1271_fetch_nvs(wl);
1372 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001373 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001374 }
1375
1376out:
1377 return ret;
1378}
1379
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001380int wl1271_plt_start(struct wl1271 *wl)
1381{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001382 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001383 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001384 int ret;
1385
1386 mutex_lock(&wl->mutex);
1387
1388 wl1271_notice("power up");
1389
1390 if (wl->state != WL1271_STATE_OFF) {
1391 wl1271_error("cannot go into PLT state because not "
1392 "in off state: %d", wl->state);
1393 ret = -EBUSY;
1394 goto out;
1395 }
1396
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001397 while (retries) {
1398 retries--;
1399 ret = wl1271_chip_wakeup(wl);
1400 if (ret < 0)
1401 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001403 ret = wl1271_boot(wl);
1404 if (ret < 0)
1405 goto power_off;
1406
1407 ret = wl1271_plt_init(wl);
1408 if (ret < 0)
1409 goto irq_disable;
1410
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001411 wl->state = WL1271_STATE_PLT;
1412 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001413 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001414
Gery Kahn6f07b722011-07-18 14:21:49 +03001415 /* update hw/fw version info in wiphy struct */
1416 wiphy->hw_version = wl->chip.id;
1417 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1418 sizeof(wiphy->fw_version));
1419
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420 goto out;
1421
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001422irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001423 mutex_unlock(&wl->mutex);
1424 /* Unlocking the mutex in the middle of handling is
1425 inherently unsafe. In this case we deem it safe to do,
1426 because we need to let any possibly pending IRQ out of
1427 the system (and while we are WL1271_STATE_OFF the IRQ
1428 work function will not do anything.) Also, any other
1429 possible concurrent operations will fail due to the
1430 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001431 wl1271_disable_interrupts(wl);
1432 wl1271_flush_deferred_work(wl);
1433 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001434 mutex_lock(&wl->mutex);
1435power_off:
1436 wl1271_power_off(wl);
1437 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001439 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1440 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441out:
1442 mutex_unlock(&wl->mutex);
1443
1444 return ret;
1445}
1446
Luciano Coelho4623ec72011-03-21 19:26:41 +02001447static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448{
1449 int ret = 0;
1450
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001451 wl1271_notice("power down");
1452
1453 if (wl->state != WL1271_STATE_PLT) {
1454 wl1271_error("cannot power down because not in PLT "
1455 "state: %d", wl->state);
1456 ret = -EBUSY;
1457 goto out;
1458 }
1459
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001460 wl1271_power_off(wl);
1461
1462 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001463 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001464
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001466 wl1271_disable_interrupts(wl);
1467 wl1271_flush_deferred_work(wl);
1468 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001469 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001470 mutex_lock(&wl->mutex);
1471out:
1472 return ret;
1473}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001474
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001475int wl1271_plt_stop(struct wl1271 *wl)
1476{
1477 int ret;
1478
1479 mutex_lock(&wl->mutex);
1480 ret = __wl1271_plt_stop(wl);
1481 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001482 return ret;
1483}
1484
Johannes Berg7bb45682011-02-24 14:42:06 +01001485static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486{
1487 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001488 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1489 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001490 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001491 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001492 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001493 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001494
Eliad Peller0f168012011-10-11 13:52:25 +02001495 if (vif)
1496 wlvif = wl12xx_vif_to_data(vif);
1497
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001498 mapping = skb_get_queue_mapping(skb);
1499 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001500
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001501 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001502
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001503 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001504
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001505 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001506 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001507 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001508 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
1509 dev_kfree_skb(skb);
1510 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001511 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001512
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001513 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1514 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1515
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001516 wl->tx_queue_count[q]++;
1517
1518 /*
1519 * The workqueue is slow to process the tx_queue and we need stop
1520 * the queue here, otherwise the queue will get too long.
1521 */
1522 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1523 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1524 ieee80211_stop_queue(wl->hw, mapping);
1525 set_bit(q, &wl->stopped_queues_map);
1526 }
1527
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001528 /*
1529 * The chip specific setup must run before the first TX packet -
1530 * before that, the tx_work will not be initialized!
1531 */
1532
Ido Yarivb07d4032011-03-01 15:14:43 +02001533 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1534 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001535 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001536
Arik Nemtsov04216da2011-08-14 13:17:38 +03001537out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001538 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001539}
1540
Shahar Leviae47c452011-03-06 16:32:14 +02001541int wl1271_tx_dummy_packet(struct wl1271 *wl)
1542{
Ido Yariv990f5de2011-03-31 10:06:59 +02001543 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001544 int q;
1545
1546 /* no need to queue a new dummy packet if one is already pending */
1547 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1548 return 0;
1549
1550 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001551
Ido Yariv990f5de2011-03-31 10:06:59 +02001552 spin_lock_irqsave(&wl->wl_lock, flags);
1553 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001554 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001555 spin_unlock_irqrestore(&wl->wl_lock, flags);
1556
1557 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1558 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001559 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001560
1561 /*
1562 * If the FW TX is busy, TX work will be scheduled by the threaded
1563 * interrupt handler function
1564 */
1565 return 0;
1566}
1567
1568/*
1569 * The size of the dummy packet should be at least 1400 bytes. However, in
1570 * order to minimize the number of bus transactions, aligning it to 512 bytes
1571 * boundaries could be beneficial, performance wise
1572 */
1573#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1574
Luciano Coelhocf27d862011-04-01 21:08:23 +03001575static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001576{
1577 struct sk_buff *skb;
1578 struct ieee80211_hdr_3addr *hdr;
1579 unsigned int dummy_packet_size;
1580
1581 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1582 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1583
1584 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001585 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001586 wl1271_warning("Failed to allocate a dummy packet skb");
1587 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001588 }
1589
1590 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1591
1592 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1593 memset(hdr, 0, sizeof(*hdr));
1594 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001595 IEEE80211_STYPE_NULLFUNC |
1596 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001597
Ido Yariv990f5de2011-03-31 10:06:59 +02001598 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001599
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001600 /* Dummy packets require the TID to be management */
1601 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001602
1603 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001604 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001605 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001606
Ido Yariv990f5de2011-03-31 10:06:59 +02001607 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001608}
1609
Ido Yariv990f5de2011-03-31 10:06:59 +02001610
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001611static struct notifier_block wl1271_dev_notifier = {
1612 .notifier_call = wl1271_dev_notify,
1613};
1614
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001615#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001616static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1617 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001618{
Eliad Pellere85d1622011-06-27 13:06:43 +03001619 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001620
Eliad Peller94390642011-05-13 11:57:13 +03001621 mutex_lock(&wl->mutex);
1622
Eliad Pellerba8447f2011-10-10 10:13:00 +02001623 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001624 goto out_unlock;
1625
Eliad Peller94390642011-05-13 11:57:13 +03001626 ret = wl1271_ps_elp_wakeup(wl);
1627 if (ret < 0)
1628 goto out_unlock;
1629
1630 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001631 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001632 DECLARE_COMPLETION_ONSTACK(compl);
1633
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001634 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001635 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001636 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001637 if (ret < 0)
1638 goto out_sleep;
1639
1640 /* we must unlock here so we will be able to get events */
1641 wl1271_ps_elp_sleep(wl);
1642 mutex_unlock(&wl->mutex);
1643
1644 ret = wait_for_completion_timeout(
1645 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1646 if (ret <= 0) {
1647 wl1271_warning("couldn't enter ps mode!");
1648 ret = -EBUSY;
1649 goto out;
1650 }
1651
1652 /* take mutex again, and wakeup */
1653 mutex_lock(&wl->mutex);
1654
1655 ret = wl1271_ps_elp_wakeup(wl);
1656 if (ret < 0)
1657 goto out_unlock;
1658 }
1659out_sleep:
1660 wl1271_ps_elp_sleep(wl);
1661out_unlock:
1662 mutex_unlock(&wl->mutex);
1663out:
1664 return ret;
1665
1666}
1667
Eliad Peller0603d892011-10-05 11:55:51 +02001668static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1669 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001670{
Eliad Pellere85d1622011-06-27 13:06:43 +03001671 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001672
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001673 mutex_lock(&wl->mutex);
1674
Eliad Peller53d40d02011-10-10 10:13:02 +02001675 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001676 goto out_unlock;
1677
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001678 ret = wl1271_ps_elp_wakeup(wl);
1679 if (ret < 0)
1680 goto out_unlock;
1681
Eliad Peller0603d892011-10-05 11:55:51 +02001682 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001683
1684 wl1271_ps_elp_sleep(wl);
1685out_unlock:
1686 mutex_unlock(&wl->mutex);
1687 return ret;
1688
1689}
1690
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001691static int wl1271_configure_suspend(struct wl1271 *wl,
1692 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001693{
Eliad Peller536129c2011-10-05 11:55:45 +02001694 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001695 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001696 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001697 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001698 return 0;
1699}
1700
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001701static void wl1271_configure_resume(struct wl1271 *wl,
1702 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001703{
1704 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001705 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1706 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001707
1708 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001709 return;
1710
1711 mutex_lock(&wl->mutex);
1712 ret = wl1271_ps_elp_wakeup(wl);
1713 if (ret < 0)
1714 goto out;
1715
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001716 if (is_sta) {
1717 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001718 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001719 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001720 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001721 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001722 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001723 }
Eliad Peller94390642011-05-13 11:57:13 +03001724
1725 wl1271_ps_elp_sleep(wl);
1726out:
1727 mutex_unlock(&wl->mutex);
1728}
1729
Eliad Peller402e48612011-05-13 11:57:09 +03001730static int wl1271_op_suspend(struct ieee80211_hw *hw,
1731 struct cfg80211_wowlan *wow)
1732{
1733 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001734 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001735 int ret;
1736
Eliad Peller402e48612011-05-13 11:57:09 +03001737 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001738 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001739
Eliad Peller4a859df2011-06-06 12:21:52 +03001740 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001741 wl12xx_for_each_wlvif(wl, wlvif) {
1742 ret = wl1271_configure_suspend(wl, wlvif);
1743 if (ret < 0) {
1744 wl1271_warning("couldn't prepare device to suspend");
1745 return ret;
1746 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001747 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001748 /* flush any remaining work */
1749 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001750
1751 /*
1752 * disable and re-enable interrupts in order to flush
1753 * the threaded_irq
1754 */
1755 wl1271_disable_interrupts(wl);
1756
1757 /*
1758 * set suspended flag to avoid triggering a new threaded_irq
1759 * work. no need for spinlock as interrupts are disabled.
1760 */
1761 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1762
1763 wl1271_enable_interrupts(wl);
1764 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001765 wl12xx_for_each_wlvif(wl, wlvif) {
1766 flush_delayed_work(&wlvif->pspoll_work);
1767 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001768 flush_delayed_work(&wl->elp_work);
1769
Eliad Peller402e48612011-05-13 11:57:09 +03001770 return 0;
1771}
1772
1773static int wl1271_op_resume(struct ieee80211_hw *hw)
1774{
1775 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001776 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001777 unsigned long flags;
1778 bool run_irq_work = false;
1779
Eliad Peller402e48612011-05-13 11:57:09 +03001780 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1781 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001782 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001783
1784 /*
1785 * re-enable irq_work enqueuing, and call irq_work directly if
1786 * there is a pending work.
1787 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001788 spin_lock_irqsave(&wl->wl_lock, flags);
1789 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1790 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1791 run_irq_work = true;
1792 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001793
Eliad Peller4a859df2011-06-06 12:21:52 +03001794 if (run_irq_work) {
1795 wl1271_debug(DEBUG_MAC80211,
1796 "run postponed irq_work directly");
1797 wl1271_irq(0, wl);
1798 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001799 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001800 wl12xx_for_each_wlvif(wl, wlvif) {
1801 wl1271_configure_resume(wl, wlvif);
1802 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001803 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001804
Eliad Peller402e48612011-05-13 11:57:09 +03001805 return 0;
1806}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001807#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001808
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001809static int wl1271_op_start(struct ieee80211_hw *hw)
1810{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001811 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1812
1813 /*
1814 * We have to delay the booting of the hardware because
1815 * we need to know the local MAC address before downloading and
1816 * initializing the firmware. The MAC address cannot be changed
1817 * after boot, and without the proper MAC address, the firmware
1818 * will not function properly.
1819 *
1820 * The MAC address is first known when the corresponding interface
1821 * is added. That is where we will initialize the hardware.
1822 */
1823
1824 return 0;
1825}
1826
1827static void wl1271_op_stop(struct ieee80211_hw *hw)
1828{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001829 struct wl1271 *wl = hw->priv;
1830 int i;
1831
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001832 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001833
Eliad Peller10c8cd02011-10-10 10:13:06 +02001834 mutex_lock(&wl->mutex);
1835 if (wl->state == WL1271_STATE_OFF) {
1836 mutex_unlock(&wl->mutex);
1837 return;
1838 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001839 /*
1840 * this must be before the cancel_work calls below, so that the work
1841 * functions don't perform further work.
1842 */
1843 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001844 mutex_unlock(&wl->mutex);
1845
1846 mutex_lock(&wl_list_mutex);
1847 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001848 mutex_unlock(&wl_list_mutex);
1849
1850 wl1271_disable_interrupts(wl);
1851 wl1271_flush_deferred_work(wl);
1852 cancel_delayed_work_sync(&wl->scan_complete_work);
1853 cancel_work_sync(&wl->netstack_work);
1854 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001855 cancel_delayed_work_sync(&wl->elp_work);
1856
1857 /* let's notify MAC80211 about the remaining pending TX frames */
1858 wl12xx_tx_reset(wl, true);
1859 mutex_lock(&wl->mutex);
1860
1861 wl1271_power_off(wl);
1862
1863 wl->band = IEEE80211_BAND_2GHZ;
1864
1865 wl->rx_counter = 0;
1866 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1867 wl->tx_blocks_available = 0;
1868 wl->tx_allocated_blocks = 0;
1869 wl->tx_results_count = 0;
1870 wl->tx_packets_count = 0;
1871 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001872 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1873 wl->ap_fw_ps_map = 0;
1874 wl->ap_ps_map = 0;
1875 wl->sched_scanning = false;
1876 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1877 memset(wl->links_map, 0, sizeof(wl->links_map));
1878 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1879 wl->active_sta_count = 0;
1880
1881 /* The system link is always allocated */
1882 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1883
1884 /*
1885 * this is performed after the cancel_work calls and the associated
1886 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1887 * get executed before all these vars have been reset.
1888 */
1889 wl->flags = 0;
1890
1891 wl->tx_blocks_freed = 0;
1892
1893 for (i = 0; i < NUM_TX_QUEUES; i++) {
1894 wl->tx_pkts_freed[i] = 0;
1895 wl->tx_allocated_pkts[i] = 0;
1896 }
1897
1898 wl1271_debugfs_reset(wl);
1899
1900 kfree(wl->fw_status);
1901 wl->fw_status = NULL;
1902 kfree(wl->tx_res_if);
1903 wl->tx_res_if = NULL;
1904 kfree(wl->target_mem_map);
1905 wl->target_mem_map = NULL;
1906
1907 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001908}
1909
Eliad Pellere5a359f2011-10-10 10:13:15 +02001910static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1911{
1912 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1913 WL12XX_MAX_RATE_POLICIES);
1914 if (policy >= WL12XX_MAX_RATE_POLICIES)
1915 return -EBUSY;
1916
1917 __set_bit(policy, wl->rate_policies_map);
1918 *idx = policy;
1919 return 0;
1920}
1921
1922static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1923{
1924 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1925 return;
1926
1927 __clear_bit(*idx, wl->rate_policies_map);
1928 *idx = WL12XX_MAX_RATE_POLICIES;
1929}
1930
Eliad Peller536129c2011-10-05 11:55:45 +02001931static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001932{
Eliad Peller536129c2011-10-05 11:55:45 +02001933 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001934 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001935 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001936 return WL1271_ROLE_P2P_GO;
1937 else
1938 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001939
1940 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001941 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001942 return WL1271_ROLE_P2P_CL;
1943 else
1944 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001945
Eliad Peller227e81e2011-08-14 13:17:26 +03001946 case BSS_TYPE_IBSS:
1947 return WL1271_ROLE_IBSS;
1948
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001949 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001950 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001951 }
1952 return WL12XX_INVALID_ROLE_TYPE;
1953}
1954
Eliad Peller83587502011-10-10 10:12:53 +02001955static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001956{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001957 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001958 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001959
Eliad Peller48e93e42011-10-10 10:12:58 +02001960 /* clear everything but the persistent data */
1961 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001962
1963 switch (ieee80211_vif_type_p2p(vif)) {
1964 case NL80211_IFTYPE_P2P_CLIENT:
1965 wlvif->p2p = 1;
1966 /* fall-through */
1967 case NL80211_IFTYPE_STATION:
1968 wlvif->bss_type = BSS_TYPE_STA_BSS;
1969 break;
1970 case NL80211_IFTYPE_ADHOC:
1971 wlvif->bss_type = BSS_TYPE_IBSS;
1972 break;
1973 case NL80211_IFTYPE_P2P_GO:
1974 wlvif->p2p = 1;
1975 /* fall-through */
1976 case NL80211_IFTYPE_AP:
1977 wlvif->bss_type = BSS_TYPE_AP_BSS;
1978 break;
1979 default:
1980 wlvif->bss_type = MAX_BSS_TYPE;
1981 return -EOPNOTSUPP;
1982 }
1983
Eliad Peller0603d892011-10-05 11:55:51 +02001984 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001985 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001986 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001987
Eliad Pellere936bbe2011-10-05 11:55:56 +02001988 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1989 wlvif->bss_type == BSS_TYPE_IBSS) {
1990 /* init sta/ibss data */
1991 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001992 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1993 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1994 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001995 } else {
1996 /* init ap data */
1997 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1998 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001999 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2000 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2001 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2002 wl12xx_allocate_rate_policy(wl,
2003 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002004 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002005
Eliad Peller83587502011-10-10 10:12:53 +02002006 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
2007 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002008 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002009 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002010 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02002011 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
2012
Eliad Peller1b92f152011-10-10 10:13:09 +02002013 /*
2014 * mac80211 configures some values globally, while we treat them
2015 * per-interface. thus, on init, we have to copy them from wl
2016 */
2017 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02002018 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02002019 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02002020
Eliad Peller9eb599e2011-10-10 10:12:59 +02002021 INIT_WORK(&wlvif->rx_streaming_enable_work,
2022 wl1271_rx_streaming_enable_work);
2023 INIT_WORK(&wlvif->rx_streaming_disable_work,
2024 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02002025 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02002026 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02002027
Eliad Peller9eb599e2011-10-10 10:12:59 +02002028 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
2029 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002030 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002031}
2032
Eliad Peller1d095472011-10-10 10:12:49 +02002033static bool wl12xx_init_fw(struct wl1271 *wl)
2034{
2035 int retries = WL1271_BOOT_RETRIES;
2036 bool booted = false;
2037 struct wiphy *wiphy = wl->hw->wiphy;
2038 int ret;
2039
2040 while (retries) {
2041 retries--;
2042 ret = wl1271_chip_wakeup(wl);
2043 if (ret < 0)
2044 goto power_off;
2045
2046 ret = wl1271_boot(wl);
2047 if (ret < 0)
2048 goto power_off;
2049
2050 ret = wl1271_hw_init(wl);
2051 if (ret < 0)
2052 goto irq_disable;
2053
2054 booted = true;
2055 break;
2056
2057irq_disable:
2058 mutex_unlock(&wl->mutex);
2059 /* Unlocking the mutex in the middle of handling is
2060 inherently unsafe. In this case we deem it safe to do,
2061 because we need to let any possibly pending IRQ out of
2062 the system (and while we are WL1271_STATE_OFF the IRQ
2063 work function will not do anything.) Also, any other
2064 possible concurrent operations will fail due to the
2065 current state, hence the wl1271 struct should be safe. */
2066 wl1271_disable_interrupts(wl);
2067 wl1271_flush_deferred_work(wl);
2068 cancel_work_sync(&wl->netstack_work);
2069 mutex_lock(&wl->mutex);
2070power_off:
2071 wl1271_power_off(wl);
2072 }
2073
2074 if (!booted) {
2075 wl1271_error("firmware boot failed despite %d retries",
2076 WL1271_BOOT_RETRIES);
2077 goto out;
2078 }
2079
2080 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2081
2082 /* update hw/fw version info in wiphy struct */
2083 wiphy->hw_version = wl->chip.id;
2084 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2085 sizeof(wiphy->fw_version));
2086
2087 /*
2088 * Now we know if 11a is supported (info from the NVS), so disable
2089 * 11a channels if not supported
2090 */
2091 if (!wl->enable_11a)
2092 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2093
2094 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2095 wl->enable_11a ? "" : "not ");
2096
2097 wl->state = WL1271_STATE_ON;
2098out:
2099 return booted;
2100}
2101
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002102static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2103 struct ieee80211_vif *vif)
2104{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002105 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002106 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002107 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002108 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002109 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002110
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002111 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002112 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002113
2114 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002115 ret = wl1271_ps_elp_wakeup(wl);
2116 if (ret < 0)
2117 goto out_unlock;
2118
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002119 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002120 wl1271_debug(DEBUG_MAC80211,
2121 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002122 ret = -EBUSY;
2123 goto out;
2124 }
2125
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002126 /*
2127 * in some very corner case HW recovery scenarios its possible to
2128 * get here before __wl1271_op_remove_interface is complete, so
2129 * opt out if that is the case.
2130 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002131 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2132 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002133 ret = -EBUSY;
2134 goto out;
2135 }
2136
Eliad Peller83587502011-10-10 10:12:53 +02002137 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002138 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002139 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002140
Eliad Peller252efa42011-10-05 11:56:00 +02002141 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002142 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002143 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2144 ret = -EINVAL;
2145 goto out;
2146 }
Eliad Peller1d095472011-10-10 10:12:49 +02002147
Eliad Peller784f6942011-10-05 11:55:39 +02002148 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002149 * TODO: after the nvs issue will be solved, move this block
2150 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002151 */
Eliad Peller1d095472011-10-10 10:12:49 +02002152 if (wl->state == WL1271_STATE_OFF) {
2153 /*
2154 * we still need this in order to configure the fw
2155 * while uploading the nvs
2156 */
2157 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002158
Eliad Peller1d095472011-10-10 10:12:49 +02002159 booted = wl12xx_init_fw(wl);
2160 if (!booted) {
2161 ret = -EINVAL;
2162 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002163 }
Eliad Peller1d095472011-10-10 10:12:49 +02002164 }
Eliad Peller04e80792011-08-14 13:17:09 +03002165
Eliad Peller1d095472011-10-10 10:12:49 +02002166 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2167 wlvif->bss_type == BSS_TYPE_IBSS) {
2168 /*
2169 * The device role is a special role used for
2170 * rx and tx frames prior to association (as
2171 * the STA role can get packets only from
2172 * its associated bssid)
2173 */
Eliad Peller784f6942011-10-05 11:55:39 +02002174 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002175 WL1271_ROLE_DEVICE,
2176 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002177 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002178 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002179 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002180
Eliad Peller1d095472011-10-10 10:12:49 +02002181 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2182 role_type, &wlvif->role_id);
2183 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002184 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002185
2186 ret = wl1271_init_vif_specific(wl, vif);
2187 if (ret < 0)
2188 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002189
2190 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002191 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002192 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002193
2194 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2195 wl->ap_count++;
2196 else
2197 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002198out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002199 wl1271_ps_elp_sleep(wl);
2200out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002201 mutex_unlock(&wl->mutex);
2202
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002203 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002204 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002205 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002206 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002207
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002208 return ret;
2209}
2210
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002211static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002212 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002213 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002214{
Eliad Peller536129c2011-10-05 11:55:45 +02002215 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002216 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002217
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002218 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002219
Eliad Peller10c8cd02011-10-10 10:13:06 +02002220 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2221 return;
2222
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002223 wl->vif = NULL;
2224
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002225 /* because of hardware recovery, we may get here twice */
2226 if (wl->state != WL1271_STATE_ON)
2227 return;
2228
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002229 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002230
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002231 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002232 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002233 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002234
Eliad Pellerbaf62772011-10-10 10:12:52 +02002235 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2236 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002237 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002238 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002239 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002240 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002241 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002242 }
2243
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002244 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2245 /* disable active roles */
2246 ret = wl1271_ps_elp_wakeup(wl);
2247 if (ret < 0)
2248 goto deinit;
2249
Eliad Peller536129c2011-10-05 11:55:45 +02002250 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002251 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002252 if (ret < 0)
2253 goto deinit;
2254 }
2255
Eliad Peller0603d892011-10-05 11:55:51 +02002256 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002257 if (ret < 0)
2258 goto deinit;
2259
2260 wl1271_ps_elp_sleep(wl);
2261 }
2262deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002263 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002264 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002265
2266 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2267 wlvif->bss_type == BSS_TYPE_IBSS) {
2268 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2269 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2270 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2271 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2272 } else {
2273 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2274 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2275 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2276 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2277 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2278 wl12xx_free_rate_policy(wl,
2279 &wlvif->ap.ucast_rate_idx[i]);
2280 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002281
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002282 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002283 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002284 if (wl->last_wlvif == wlvif)
2285 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002286 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002287 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002288 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002289 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002290
Eliad Pellera4e41302011-10-11 11:49:15 +02002291 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2292 wl->ap_count--;
2293 else
2294 wl->sta_count--;
2295
Eliad Pellerbaf62772011-10-10 10:12:52 +02002296 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002297 del_timer_sync(&wlvif->rx_streaming_timer);
2298 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2299 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002300 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002301
Eliad Pellerbaf62772011-10-10 10:12:52 +02002302 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002303}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002304
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002305static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2306 struct ieee80211_vif *vif)
2307{
2308 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002309 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002310 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002311
2312 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002313
2314 if (wl->state == WL1271_STATE_OFF ||
2315 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2316 goto out;
2317
Juuso Oikarinen67353292010-11-18 15:19:02 +02002318 /*
2319 * wl->vif can be null here if someone shuts down the interface
2320 * just when hardware recovery has been started.
2321 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002322 wl12xx_for_each_wlvif(wl, iter) {
2323 if (iter != wlvif)
2324 continue;
2325
Eliad Peller536129c2011-10-05 11:55:45 +02002326 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002327 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002328 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002329 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002330out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002331 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002332 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002333}
2334
Eliad Peller87fbcb02011-10-05 11:55:41 +02002335static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2336 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002337{
2338 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002339 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002340
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002341 /*
2342 * One of the side effects of the JOIN command is that is clears
2343 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2344 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002345 * Currently the only valid scenario for JOIN during association
2346 * is on roaming, in which case we will also be given new keys.
2347 * Keep the below message for now, unless it starts bothering
2348 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002349 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002350 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002351 wl1271_info("JOIN while associated.");
2352
2353 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002354 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002355
Eliad Peller227e81e2011-08-14 13:17:26 +03002356 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002357 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002358 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002359 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002360 if (ret < 0)
2361 goto out;
2362
Eliad Pellerba8447f2011-10-10 10:13:00 +02002363 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002364 goto out;
2365
2366 /*
2367 * The join command disable the keep-alive mode, shut down its process,
2368 * and also clear the template config, so we need to reset it all after
2369 * the join. The acx_aid starts the keep-alive process, and the order
2370 * of the commands below is relevant.
2371 */
Eliad Peller0603d892011-10-05 11:55:51 +02002372 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002373 if (ret < 0)
2374 goto out;
2375
Eliad Peller0603d892011-10-05 11:55:51 +02002376 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002377 if (ret < 0)
2378 goto out;
2379
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002380 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002381 if (ret < 0)
2382 goto out;
2383
Eliad Peller0603d892011-10-05 11:55:51 +02002384 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2385 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002386 ACX_KEEP_ALIVE_TPL_VALID);
2387 if (ret < 0)
2388 goto out;
2389
2390out:
2391 return ret;
2392}
2393
Eliad Peller0603d892011-10-05 11:55:51 +02002394static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002395{
2396 int ret;
2397
Eliad Peller52630c52011-10-10 10:13:08 +02002398 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002399 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2400
Shahar Levi6d158ff2011-09-08 13:01:33 +03002401 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002402 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002403 }
2404
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002405 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002406 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002407 if (ret < 0)
2408 goto out;
2409
Oz Krakowskib992c682011-06-26 10:36:02 +03002410 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002411 wlvif->tx_security_last_seq_lsb = 0;
2412 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002413
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002414out:
2415 return ret;
2416}
2417
Eliad Peller87fbcb02011-10-05 11:55:41 +02002418static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002419{
Eliad Peller1b92f152011-10-10 10:13:09 +02002420 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002421 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002422}
2423
Eliad Peller251c1772011-08-14 13:17:17 +03002424static bool wl12xx_is_roc(struct wl1271 *wl)
2425{
2426 u8 role_id;
2427
2428 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2429 if (role_id >= WL12XX_MAX_ROLES)
2430 return false;
2431
2432 return true;
2433}
2434
Eliad Peller87fbcb02011-10-05 11:55:41 +02002435static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2436 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002437{
2438 int ret;
2439
2440 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002441 /* no need to croc if we weren't busy (e.g. during boot) */
2442 if (wl12xx_is_roc(wl)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002443 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002444 if (ret < 0)
2445 goto out;
2446 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002447 wlvif->rate_set =
2448 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2449 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002450 if (ret < 0)
2451 goto out;
2452 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002453 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002454 ACX_KEEP_ALIVE_TPL_INVALID);
2455 if (ret < 0)
2456 goto out;
2457 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2458 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002459 /* The current firmware only supports sched_scan in idle */
2460 if (wl->sched_scanning) {
2461 wl1271_scan_sched_scan_stop(wl);
2462 ieee80211_sched_scan_stopped(wl->hw);
2463 }
2464
Eliad Peller679a6732011-10-11 11:55:44 +02002465 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002466 if (ret < 0)
2467 goto out;
2468 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2469 }
2470
2471out:
2472 return ret;
2473}
2474
Eliad Peller9f259c42011-10-10 10:13:12 +02002475static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2476 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002477{
Eliad Peller9f259c42011-10-10 10:13:12 +02002478 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2479 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002480
2481 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2482
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002483 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002484 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002485 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002486 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002487 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002488 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002489 wlvif->band = conf->channel->band;
2490 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002491
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002492 if (!is_ap) {
2493 /*
2494 * FIXME: the mac80211 should really provide a fixed
2495 * rate to use here. for now, just use the smallest
2496 * possible rate for the band as a fixed rate for
2497 * association frames and other control messages.
2498 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002499 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002500 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002501
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002502 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002503 wl1271_tx_min_rate_get(wl,
2504 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002505 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002506 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002507 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002508 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002509
Eliad Pellerba8447f2011-10-10 10:13:00 +02002510 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2511 &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002512 if (wl12xx_is_roc(wl)) {
2513 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002514 ret = wl12xx_croc(wl,
2515 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002516 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002517 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002518 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002519 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002520 if (ret < 0)
2521 wl1271_warning("cmd join on channel "
2522 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002523 } else {
2524 /*
2525 * change the ROC channel. do it only if we are
2526 * not idle. otherwise, CROC will be called
2527 * anyway.
2528 */
2529 if (wl12xx_is_roc(wl) &&
2530 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002531 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002532 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002533 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002534
Eliad Peller679a6732011-10-11 11:55:44 +02002535 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002536 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002537 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002538 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002539 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002540 }
2541 }
2542
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002543 /*
2544 * if mac80211 changes the PSM mode, make sure the mode is not
2545 * incorrectly changed after the pspoll failure active window.
2546 */
2547 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002548 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002549
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002550 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002551 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2552 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002553
2554 /*
2555 * We enter PSM only if we're already associated.
2556 * If we're not, we'll enter it when joining an SSID,
2557 * through the bss_info_changed() hook.
2558 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002559 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002560 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002561 ret = wl1271_ps_set_mode(wl, wlvif,
2562 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002563 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002564 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002565 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002566 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002567 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002568
Eliad Pellerc29bb002011-10-10 10:13:03 +02002569 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002570
Eliad Pellerc29bb002011-10-10 10:13:03 +02002571 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002572 ret = wl1271_ps_set_mode(wl, wlvif,
2573 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002574 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002575 }
2576
Eliad Peller6bd65022011-10-10 10:13:11 +02002577 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002578 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002579 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002580 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002581
Eliad Peller6bd65022011-10-10 10:13:11 +02002582 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002583 }
2584
Eliad Peller9f259c42011-10-10 10:13:12 +02002585 return 0;
2586}
2587
2588static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2589{
2590 struct wl1271 *wl = hw->priv;
2591 struct wl12xx_vif *wlvif;
2592 struct ieee80211_conf *conf = &hw->conf;
2593 int channel, ret = 0;
2594
2595 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2596
2597 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2598 " changed 0x%x",
2599 channel,
2600 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2601 conf->power_level,
2602 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2603 changed);
2604
2605 /*
2606 * mac80211 will go to idle nearly immediately after transmitting some
2607 * frames, such as the deauth. To make sure those frames reach the air,
2608 * wait here until the TX queue is fully flushed.
2609 */
2610 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2611 (conf->flags & IEEE80211_CONF_IDLE))
2612 wl1271_tx_flush(wl);
2613
2614 mutex_lock(&wl->mutex);
2615
2616 /* we support configuring the channel and band even while off */
2617 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2618 wl->band = conf->channel->band;
2619 wl->channel = channel;
2620 }
2621
2622 if (changed & IEEE80211_CONF_CHANGE_POWER)
2623 wl->power_level = conf->power_level;
2624
2625 if (unlikely(wl->state == WL1271_STATE_OFF))
2626 goto out;
2627
2628 ret = wl1271_ps_elp_wakeup(wl);
2629 if (ret < 0)
2630 goto out;
2631
2632 /* configure each interface */
2633 wl12xx_for_each_wlvif(wl, wlvif) {
2634 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2635 if (ret < 0)
2636 goto out_sleep;
2637 }
2638
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002639out_sleep:
2640 wl1271_ps_elp_sleep(wl);
2641
2642out:
2643 mutex_unlock(&wl->mutex);
2644
2645 return ret;
2646}
2647
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002648struct wl1271_filter_params {
2649 bool enabled;
2650 int mc_list_length;
2651 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2652};
2653
Jiri Pirko22bedad2010-04-01 21:22:57 +00002654static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2655 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002656{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002657 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002658 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002659 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002660
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002661 if (unlikely(wl->state == WL1271_STATE_OFF))
2662 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002663
Juuso Oikarinen74441132009-10-13 12:47:53 +03002664 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002665 if (!fp) {
2666 wl1271_error("Out of memory setting filters.");
2667 return 0;
2668 }
2669
2670 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002671 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002672 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2673 fp->enabled = false;
2674 } else {
2675 fp->enabled = true;
2676 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002677 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002678 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002679 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002680 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002681 }
2682
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002683 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002684}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002685
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002686#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2687 FIF_ALLMULTI | \
2688 FIF_FCSFAIL | \
2689 FIF_BCN_PRBRESP_PROMISC | \
2690 FIF_CONTROL | \
2691 FIF_OTHER_BSS)
2692
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002693static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2694 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002695 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002696{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002697 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002698 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002699 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002700
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002701 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002702
Arik Nemtsov7d057862010-10-16 19:25:35 +02002703 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2704 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002705
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002706 mutex_lock(&wl->mutex);
2707
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002708 *total &= WL1271_SUPPORTED_FILTERS;
2709 changed &= WL1271_SUPPORTED_FILTERS;
2710
2711 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002712 goto out;
2713
Ido Yariva6208652011-03-01 15:14:41 +02002714 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002715 if (ret < 0)
2716 goto out;
2717
Eliad Peller6e8cd332011-10-10 10:13:13 +02002718 wl12xx_for_each_wlvif(wl, wlvif) {
2719 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2720 if (*total & FIF_ALLMULTI)
2721 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2722 false,
2723 NULL, 0);
2724 else if (fp)
2725 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2726 fp->enabled,
2727 fp->mc_list,
2728 fp->mc_list_length);
2729 if (ret < 0)
2730 goto out_sleep;
2731 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002732 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002733
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002734 /*
2735 * the fw doesn't provide an api to configure the filters. instead,
2736 * the filters configuration is based on the active roles / ROC
2737 * state.
2738 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002739
2740out_sleep:
2741 wl1271_ps_elp_sleep(wl);
2742
2743out:
2744 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002745 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002746}
2747
Eliad Peller170d0e62011-10-05 11:56:06 +02002748static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2749 u8 id, u8 key_type, u8 key_size,
2750 const u8 *key, u8 hlid, u32 tx_seq_32,
2751 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002752{
2753 struct wl1271_ap_key *ap_key;
2754 int i;
2755
2756 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2757
2758 if (key_size > MAX_KEY_SIZE)
2759 return -EINVAL;
2760
2761 /*
2762 * Find next free entry in ap_keys. Also check we are not replacing
2763 * an existing key.
2764 */
2765 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002766 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002767 break;
2768
Eliad Peller170d0e62011-10-05 11:56:06 +02002769 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002770 wl1271_warning("trying to record key replacement");
2771 return -EINVAL;
2772 }
2773 }
2774
2775 if (i == MAX_NUM_KEYS)
2776 return -EBUSY;
2777
2778 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2779 if (!ap_key)
2780 return -ENOMEM;
2781
2782 ap_key->id = id;
2783 ap_key->key_type = key_type;
2784 ap_key->key_size = key_size;
2785 memcpy(ap_key->key, key, key_size);
2786 ap_key->hlid = hlid;
2787 ap_key->tx_seq_32 = tx_seq_32;
2788 ap_key->tx_seq_16 = tx_seq_16;
2789
Eliad Peller170d0e62011-10-05 11:56:06 +02002790 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002791 return 0;
2792}
2793
Eliad Peller170d0e62011-10-05 11:56:06 +02002794static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002795{
2796 int i;
2797
2798 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002799 kfree(wlvif->ap.recorded_keys[i]);
2800 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002801 }
2802}
2803
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002804static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002805{
2806 int i, ret = 0;
2807 struct wl1271_ap_key *key;
2808 bool wep_key_added = false;
2809
2810 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002811 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002812 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002813 break;
2814
Eliad Peller170d0e62011-10-05 11:56:06 +02002815 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002816 hlid = key->hlid;
2817 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002818 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002819
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002820 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002821 key->id, key->key_type,
2822 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002823 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002824 key->tx_seq_16);
2825 if (ret < 0)
2826 goto out;
2827
2828 if (key->key_type == KEY_WEP)
2829 wep_key_added = true;
2830 }
2831
2832 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002833 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002834 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002835 if (ret < 0)
2836 goto out;
2837 }
2838
2839out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002840 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002841 return ret;
2842}
2843
Eliad Peller536129c2011-10-05 11:55:45 +02002844static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2845 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002846 u8 key_size, const u8 *key, u32 tx_seq_32,
2847 u16 tx_seq_16, struct ieee80211_sta *sta)
2848{
2849 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002850 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002851
2852 if (is_ap) {
2853 struct wl1271_station *wl_sta;
2854 u8 hlid;
2855
2856 if (sta) {
2857 wl_sta = (struct wl1271_station *)sta->drv_priv;
2858 hlid = wl_sta->hlid;
2859 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002860 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002861 }
2862
Eliad Peller53d40d02011-10-10 10:13:02 +02002863 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002864 /*
2865 * We do not support removing keys after AP shutdown.
2866 * Pretend we do to make mac80211 happy.
2867 */
2868 if (action != KEY_ADD_OR_REPLACE)
2869 return 0;
2870
Eliad Peller170d0e62011-10-05 11:56:06 +02002871 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002872 key_type, key_size,
2873 key, hlid, tx_seq_32,
2874 tx_seq_16);
2875 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002876 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002877 id, key_type, key_size,
2878 key, hlid, tx_seq_32,
2879 tx_seq_16);
2880 }
2881
2882 if (ret < 0)
2883 return ret;
2884 } else {
2885 const u8 *addr;
2886 static const u8 bcast_addr[ETH_ALEN] = {
2887 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2888 };
2889
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002890 /*
2891 * A STA set to GEM cipher requires 2 tx spare blocks.
2892 * Return to default value when GEM cipher key is removed
2893 */
2894 if (key_type == KEY_GEM) {
2895 if (action == KEY_ADD_OR_REPLACE)
2896 wl->tx_spare_blocks = 2;
2897 else if (action == KEY_REMOVE)
2898 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2899 }
2900
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002901 addr = sta ? sta->addr : bcast_addr;
2902
2903 if (is_zero_ether_addr(addr)) {
2904 /* We dont support TX only encryption */
2905 return -EOPNOTSUPP;
2906 }
2907
2908 /* The wl1271 does not allow to remove unicast keys - they
2909 will be cleared automatically on next CMD_JOIN. Ignore the
2910 request silently, as we dont want the mac80211 to emit
2911 an error message. */
2912 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2913 return 0;
2914
Eliad Peller010d3d32011-08-14 13:17:31 +03002915 /* don't remove key if hlid was already deleted */
2916 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002917 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002918 return 0;
2919
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002920 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002921 id, key_type, key_size,
2922 key, addr, tx_seq_32,
2923 tx_seq_16);
2924 if (ret < 0)
2925 return ret;
2926
2927 /* the default WEP key needs to be configured at least once */
2928 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002929 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002930 wlvif->default_key,
2931 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002932 if (ret < 0)
2933 return ret;
2934 }
2935 }
2936
2937 return 0;
2938}
2939
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002940static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2941 struct ieee80211_vif *vif,
2942 struct ieee80211_sta *sta,
2943 struct ieee80211_key_conf *key_conf)
2944{
2945 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002946 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002947 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002948 u32 tx_seq_32 = 0;
2949 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002950 u8 key_type;
2951
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002952 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2953
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002954 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002955 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002956 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002957 key_conf->keylen, key_conf->flags);
2958 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2959
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002960 mutex_lock(&wl->mutex);
2961
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002962 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2963 ret = -EAGAIN;
2964 goto out_unlock;
2965 }
2966
Ido Yariva6208652011-03-01 15:14:41 +02002967 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002968 if (ret < 0)
2969 goto out_unlock;
2970
Johannes Berg97359d12010-08-10 09:46:38 +02002971 switch (key_conf->cipher) {
2972 case WLAN_CIPHER_SUITE_WEP40:
2973 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002974 key_type = KEY_WEP;
2975
2976 key_conf->hw_key_idx = key_conf->keyidx;
2977 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002978 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002979 key_type = KEY_TKIP;
2980
2981 key_conf->hw_key_idx = key_conf->keyidx;
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);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002984 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002985 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002986 key_type = KEY_AES;
2987
2988 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Eliad Peller48e93e42011-10-10 10:12:58 +02002989 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2990 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002991 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002992 case WL1271_CIPHER_SUITE_GEM:
2993 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002994 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2995 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002996 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002997 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002998 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002999
3000 ret = -EOPNOTSUPP;
3001 goto out_sleep;
3002 }
3003
3004 switch (cmd) {
3005 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003006 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003007 key_conf->keyidx, key_type,
3008 key_conf->keylen, key_conf->key,
3009 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003010 if (ret < 0) {
3011 wl1271_error("Could not add or replace key");
3012 goto out_sleep;
3013 }
3014 break;
3015
3016 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003017 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003018 key_conf->keyidx, key_type,
3019 key_conf->keylen, key_conf->key,
3020 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003021 if (ret < 0) {
3022 wl1271_error("Could not remove key");
3023 goto out_sleep;
3024 }
3025 break;
3026
3027 default:
3028 wl1271_error("Unsupported key cmd 0x%x", cmd);
3029 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003030 break;
3031 }
3032
3033out_sleep:
3034 wl1271_ps_elp_sleep(wl);
3035
3036out_unlock:
3037 mutex_unlock(&wl->mutex);
3038
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003039 return ret;
3040}
3041
3042static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003043 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003044 struct cfg80211_scan_request *req)
3045{
3046 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003047 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3048
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003049 int ret;
3050 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003051 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003052
3053 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3054
3055 if (req->n_ssids) {
3056 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003057 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003058 }
3059
3060 mutex_lock(&wl->mutex);
3061
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003062 if (wl->state == WL1271_STATE_OFF) {
3063 /*
3064 * We cannot return -EBUSY here because cfg80211 will expect
3065 * a call to ieee80211_scan_completed if we do - in this case
3066 * there won't be any call.
3067 */
3068 ret = -EAGAIN;
3069 goto out;
3070 }
3071
Ido Yariva6208652011-03-01 15:14:41 +02003072 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003073 if (ret < 0)
3074 goto out;
3075
Eliad Peller251c1772011-08-14 13:17:17 +03003076 /* cancel ROC before scanning */
3077 if (wl12xx_is_roc(wl)) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02003078 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03003079 /* don't allow scanning right now */
3080 ret = -EBUSY;
3081 goto out_sleep;
3082 }
Eliad Peller679a6732011-10-11 11:55:44 +02003083 wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003084 }
3085
Eliad Peller784f6942011-10-05 11:55:39 +02003086 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003087out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003088 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003089out:
3090 mutex_unlock(&wl->mutex);
3091
3092 return ret;
3093}
3094
Eliad Peller73ecce32011-06-27 13:06:45 +03003095static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3096 struct ieee80211_vif *vif)
3097{
3098 struct wl1271 *wl = hw->priv;
3099 int ret;
3100
3101 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3102
3103 mutex_lock(&wl->mutex);
3104
3105 if (wl->state == WL1271_STATE_OFF)
3106 goto out;
3107
3108 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3109 goto out;
3110
3111 ret = wl1271_ps_elp_wakeup(wl);
3112 if (ret < 0)
3113 goto out;
3114
3115 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3116 ret = wl1271_scan_stop(wl);
3117 if (ret < 0)
3118 goto out_sleep;
3119 }
3120 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3121 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003122 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003123 wl->scan.req = NULL;
3124 ieee80211_scan_completed(wl->hw, true);
3125
3126out_sleep:
3127 wl1271_ps_elp_sleep(wl);
3128out:
3129 mutex_unlock(&wl->mutex);
3130
3131 cancel_delayed_work_sync(&wl->scan_complete_work);
3132}
3133
Luciano Coelho33c2c062011-05-10 14:46:02 +03003134static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3135 struct ieee80211_vif *vif,
3136 struct cfg80211_sched_scan_request *req,
3137 struct ieee80211_sched_scan_ies *ies)
3138{
3139 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003140 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003141 int ret;
3142
3143 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3144
3145 mutex_lock(&wl->mutex);
3146
3147 ret = wl1271_ps_elp_wakeup(wl);
3148 if (ret < 0)
3149 goto out;
3150
Eliad Peller536129c2011-10-05 11:55:45 +02003151 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003152 if (ret < 0)
3153 goto out_sleep;
3154
Eliad Peller536129c2011-10-05 11:55:45 +02003155 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003156 if (ret < 0)
3157 goto out_sleep;
3158
3159 wl->sched_scanning = true;
3160
3161out_sleep:
3162 wl1271_ps_elp_sleep(wl);
3163out:
3164 mutex_unlock(&wl->mutex);
3165 return ret;
3166}
3167
3168static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3169 struct ieee80211_vif *vif)
3170{
3171 struct wl1271 *wl = hw->priv;
3172 int ret;
3173
3174 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3175
3176 mutex_lock(&wl->mutex);
3177
3178 ret = wl1271_ps_elp_wakeup(wl);
3179 if (ret < 0)
3180 goto out;
3181
3182 wl1271_scan_sched_scan_stop(wl);
3183
3184 wl1271_ps_elp_sleep(wl);
3185out:
3186 mutex_unlock(&wl->mutex);
3187}
3188
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003189static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3190{
3191 struct wl1271 *wl = hw->priv;
3192 int ret = 0;
3193
3194 mutex_lock(&wl->mutex);
3195
3196 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3197 ret = -EAGAIN;
3198 goto out;
3199 }
3200
Ido Yariva6208652011-03-01 15:14:41 +02003201 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003202 if (ret < 0)
3203 goto out;
3204
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003205 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003206 if (ret < 0)
3207 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3208
3209 wl1271_ps_elp_sleep(wl);
3210
3211out:
3212 mutex_unlock(&wl->mutex);
3213
3214 return ret;
3215}
3216
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003217static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3218{
3219 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003220 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003221 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003222
3223 mutex_lock(&wl->mutex);
3224
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003225 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3226 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003227 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003228 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003229
Ido Yariva6208652011-03-01 15:14:41 +02003230 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003231 if (ret < 0)
3232 goto out;
3233
Eliad Peller6e8cd332011-10-10 10:13:13 +02003234 wl12xx_for_each_wlvif(wl, wlvif) {
3235 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3236 if (ret < 0)
3237 wl1271_warning("set rts threshold failed: %d", ret);
3238 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003239 wl1271_ps_elp_sleep(wl);
3240
3241out:
3242 mutex_unlock(&wl->mutex);
3243
3244 return ret;
3245}
3246
Eliad Peller1fe9f162011-10-05 11:55:48 +02003247static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003248 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003249{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003250 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003251 u8 ssid_len;
3252 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3253 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003254
Eliad Peller889cb362011-05-01 09:56:45 +03003255 if (!ptr) {
3256 wl1271_error("No SSID in IEs!");
3257 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003258 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003259
Eliad Peller889cb362011-05-01 09:56:45 +03003260 ssid_len = ptr[1];
3261 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3262 wl1271_error("SSID is too long!");
3263 return -EINVAL;
3264 }
3265
Eliad Peller1fe9f162011-10-05 11:55:48 +02003266 wlvif->ssid_len = ssid_len;
3267 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003268 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003269}
3270
Eliad Pellerd48055d2011-09-15 12:07:04 +03003271static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3272{
3273 int len;
3274 const u8 *next, *end = skb->data + skb->len;
3275 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3276 skb->len - ieoffset);
3277 if (!ie)
3278 return;
3279 len = ie[1] + 2;
3280 next = ie + len;
3281 memmove(ie, next, end - next);
3282 skb_trim(skb, skb->len - len);
3283}
3284
Eliad Peller26b4bf22011-09-15 12:07:05 +03003285static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3286 unsigned int oui, u8 oui_type,
3287 int ieoffset)
3288{
3289 int len;
3290 const u8 *next, *end = skb->data + skb->len;
3291 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3292 skb->data + ieoffset,
3293 skb->len - ieoffset);
3294 if (!ie)
3295 return;
3296 len = ie[1] + 2;
3297 next = ie + len;
3298 memmove(ie, next, end - next);
3299 skb_trim(skb, skb->len - len);
3300}
3301
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003302static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3303 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003304{
3305 struct sk_buff *skb;
3306 int ret;
3307
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003308 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003309 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003310 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003311
3312 ret = wl1271_cmd_template_set(wl,
3313 CMD_TEMPL_AP_PROBE_RESPONSE,
3314 skb->data,
3315 skb->len, 0,
3316 rates);
3317
3318 dev_kfree_skb(skb);
3319 return ret;
3320}
3321
3322static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3323 struct ieee80211_vif *vif,
3324 u8 *probe_rsp_data,
3325 size_t probe_rsp_len,
3326 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003327{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003328 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3329 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003330 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3331 int ssid_ie_offset, ie_offset, templ_len;
3332 const u8 *ptr;
3333
3334 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003335 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003336 return wl1271_cmd_template_set(wl,
3337 CMD_TEMPL_AP_PROBE_RESPONSE,
3338 probe_rsp_data,
3339 probe_rsp_len, 0,
3340 rates);
3341
3342 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3343 wl1271_error("probe_rsp template too big");
3344 return -EINVAL;
3345 }
3346
3347 /* start searching from IE offset */
3348 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3349
3350 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3351 probe_rsp_len - ie_offset);
3352 if (!ptr) {
3353 wl1271_error("No SSID in beacon!");
3354 return -EINVAL;
3355 }
3356
3357 ssid_ie_offset = ptr - probe_rsp_data;
3358 ptr += (ptr[1] + 2);
3359
3360 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3361
3362 /* insert SSID from bss_conf */
3363 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3364 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3365 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3366 bss_conf->ssid, bss_conf->ssid_len);
3367 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3368
3369 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3370 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3371 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3372
3373 return wl1271_cmd_template_set(wl,
3374 CMD_TEMPL_AP_PROBE_RESPONSE,
3375 probe_rsp_templ,
3376 templ_len, 0,
3377 rates);
3378}
3379
Arik Nemtsove78a2872010-10-16 19:07:21 +02003380static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003381 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003382 struct ieee80211_bss_conf *bss_conf,
3383 u32 changed)
3384{
Eliad Peller0603d892011-10-05 11:55:51 +02003385 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003386 int ret = 0;
3387
3388 if (changed & BSS_CHANGED_ERP_SLOT) {
3389 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003390 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003391 else
Eliad Peller0603d892011-10-05 11:55:51 +02003392 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003393 if (ret < 0) {
3394 wl1271_warning("Set slot time failed %d", ret);
3395 goto out;
3396 }
3397 }
3398
3399 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3400 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003401 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003402 else
Eliad Peller0603d892011-10-05 11:55:51 +02003403 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003404 }
3405
3406 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3407 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003408 ret = wl1271_acx_cts_protect(wl, wlvif,
3409 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003410 else
Eliad Peller0603d892011-10-05 11:55:51 +02003411 ret = wl1271_acx_cts_protect(wl, wlvif,
3412 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003413 if (ret < 0) {
3414 wl1271_warning("Set ctsprotect failed %d", ret);
3415 goto out;
3416 }
3417 }
3418
3419out:
3420 return ret;
3421}
3422
3423static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3424 struct ieee80211_vif *vif,
3425 struct ieee80211_bss_conf *bss_conf,
3426 u32 changed)
3427{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003428 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003429 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003430 int ret = 0;
3431
3432 if ((changed & BSS_CHANGED_BEACON_INT)) {
3433 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3434 bss_conf->beacon_int);
3435
Eliad Peller6a899792011-10-05 11:55:58 +02003436 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003437 }
3438
Arik Nemtsov560f0022011-11-08 18:46:54 +02003439 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3440 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003441 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3442 wl1271_debug(DEBUG_AP, "probe response updated");
3443 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3444 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003445 }
3446
Arik Nemtsove78a2872010-10-16 19:07:21 +02003447 if ((changed & BSS_CHANGED_BEACON)) {
3448 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003449 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003450 int ieoffset = offsetof(struct ieee80211_mgmt,
3451 u.beacon.variable);
3452 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3453 u16 tmpl_id;
3454
Arik Nemtsov560f0022011-11-08 18:46:54 +02003455 if (!beacon) {
3456 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003457 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003458 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003459
3460 wl1271_debug(DEBUG_MASTER, "beacon updated");
3461
Eliad Peller1fe9f162011-10-05 11:55:48 +02003462 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003463 if (ret < 0) {
3464 dev_kfree_skb(beacon);
3465 goto out;
3466 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003467 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003468 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3469 CMD_TEMPL_BEACON;
3470 ret = wl1271_cmd_template_set(wl, tmpl_id,
3471 beacon->data,
3472 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003473 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003474 if (ret < 0) {
3475 dev_kfree_skb(beacon);
3476 goto out;
3477 }
3478
Arik Nemtsov560f0022011-11-08 18:46:54 +02003479 /*
3480 * In case we already have a probe-resp beacon set explicitly
3481 * by usermode, don't use the beacon data.
3482 */
3483 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3484 goto end_bcn;
3485
Eliad Pellerd48055d2011-09-15 12:07:04 +03003486 /* remove TIM ie from probe response */
3487 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3488
Eliad Peller26b4bf22011-09-15 12:07:05 +03003489 /*
3490 * remove p2p ie from probe response.
3491 * the fw reponds to probe requests that don't include
3492 * the p2p ie. probe requests with p2p ie will be passed,
3493 * and will be responded by the supplicant (the spec
3494 * forbids including the p2p ie when responding to probe
3495 * requests that didn't include it).
3496 */
3497 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3498 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3499
Arik Nemtsove78a2872010-10-16 19:07:21 +02003500 hdr = (struct ieee80211_hdr *) beacon->data;
3501 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3502 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003503 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003504 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003505 beacon->data,
3506 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003507 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003508 else
3509 ret = wl1271_cmd_template_set(wl,
3510 CMD_TEMPL_PROBE_RESPONSE,
3511 beacon->data,
3512 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003513 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003514end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003515 dev_kfree_skb(beacon);
3516 if (ret < 0)
3517 goto out;
3518 }
3519
3520out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003521 if (ret != 0)
3522 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003523 return ret;
3524}
3525
3526/* AP mode changes */
3527static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003528 struct ieee80211_vif *vif,
3529 struct ieee80211_bss_conf *bss_conf,
3530 u32 changed)
3531{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003532 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003533 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003534
Arik Nemtsove78a2872010-10-16 19:07:21 +02003535 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3536 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003537
Eliad Peller87fbcb02011-10-05 11:55:41 +02003538 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003539 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003540 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003541 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003542
Eliad Peller87fbcb02011-10-05 11:55:41 +02003543 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003544 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003545 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003546 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003547 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003548
Eliad Peller784f6942011-10-05 11:55:39 +02003549 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003550 if (ret < 0)
3551 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003552 }
3553
Arik Nemtsove78a2872010-10-16 19:07:21 +02003554 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3555 if (ret < 0)
3556 goto out;
3557
3558 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3559 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003560 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003561 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003562 if (ret < 0)
3563 goto out;
3564
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003565 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003566 if (ret < 0)
3567 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003568
Eliad Peller53d40d02011-10-10 10:13:02 +02003569 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003570 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003571 }
3572 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003573 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003574 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003575 if (ret < 0)
3576 goto out;
3577
Eliad Peller53d40d02011-10-10 10:13:02 +02003578 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003579 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3580 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003581 wl1271_debug(DEBUG_AP, "stopped AP");
3582 }
3583 }
3584 }
3585
Eliad Peller0603d892011-10-05 11:55:51 +02003586 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003587 if (ret < 0)
3588 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003589
3590 /* Handle HT information change */
3591 if ((changed & BSS_CHANGED_HT) &&
3592 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003593 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003594 bss_conf->ht_operation_mode);
3595 if (ret < 0) {
3596 wl1271_warning("Set ht information failed %d", ret);
3597 goto out;
3598 }
3599 }
3600
Arik Nemtsove78a2872010-10-16 19:07:21 +02003601out:
3602 return;
3603}
3604
3605/* STA/IBSS mode changes */
3606static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3607 struct ieee80211_vif *vif,
3608 struct ieee80211_bss_conf *bss_conf,
3609 u32 changed)
3610{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003611 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003612 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003613 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003614 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003615 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003616 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003617 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003618 bool sta_exists = false;
3619 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003620
3621 if (is_ibss) {
3622 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3623 changed);
3624 if (ret < 0)
3625 goto out;
3626 }
3627
Eliad Peller227e81e2011-08-14 13:17:26 +03003628 if (changed & BSS_CHANGED_IBSS) {
3629 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003630 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003631 ibss_joined = true;
3632 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003633 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3634 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003635 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003636 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003637 }
3638 }
3639 }
3640
3641 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003642 do_join = true;
3643
3644 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003645 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003646 do_join = true;
3647
Eliad Peller227e81e2011-08-14 13:17:26 +03003648 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003649 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3650 bss_conf->enable_beacon ? "enabled" : "disabled");
3651
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003652 do_join = true;
3653 }
3654
Eliad Pellerc31e4942011-10-23 08:21:55 +02003655 if (changed & BSS_CHANGED_IDLE) {
3656 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3657 if (ret < 0)
3658 wl1271_warning("idle mode change failed %d", ret);
3659 }
3660
Arik Nemtsove78a2872010-10-16 19:07:21 +02003661 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003662 bool enable = false;
3663 if (bss_conf->cqm_rssi_thold)
3664 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003665 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003666 bss_conf->cqm_rssi_thold,
3667 bss_conf->cqm_rssi_hyst);
3668 if (ret < 0)
3669 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003670 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003671 }
3672
Eliad Pellercdf09492011-10-05 11:55:44 +02003673 if (changed & BSS_CHANGED_BSSID)
3674 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003675 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003676 if (ret < 0)
3677 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003678
Eliad Peller784f6942011-10-05 11:55:39 +02003679 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003680 if (ret < 0)
3681 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003682
Eliad Pellerfa287b82010-12-26 09:27:50 +01003683 /* Need to update the BSSID (for filtering etc) */
3684 do_join = true;
3685 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003686
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003687 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3688 rcu_read_lock();
3689 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3690 if (!sta)
3691 goto sta_not_found;
3692
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003693 /* save the supp_rates of the ap */
3694 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3695 if (sta->ht_cap.ht_supported)
3696 sta_rate_set |=
3697 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003698 sta_ht_cap = sta->ht_cap;
3699 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003700
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003701sta_not_found:
3702 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003703 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003704
Arik Nemtsove78a2872010-10-16 19:07:21 +02003705 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003706 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003707 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003708 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003709 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003710 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003711
Eliad Peller74ec8392011-10-05 11:56:02 +02003712 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003713
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003714 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003715 * use basic rates from AP, and determine lowest rate
3716 * to use with control frames.
3717 */
3718 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003719 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003720 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003721 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003722 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003723 wl1271_tx_min_rate_get(wl,
3724 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003725 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003726 wlvif->rate_set =
3727 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003728 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003729 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003730 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003731 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003732 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003733
3734 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003735 * with wl1271, we don't need to update the
3736 * beacon_int and dtim_period, because the firmware
3737 * updates it by itself when the first beacon is
3738 * received after a join.
3739 */
Eliad Peller6840e372011-10-05 11:55:50 +02003740 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003741 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003742 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003743
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003744 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003745 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003746 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003747 dev_kfree_skb(wlvif->probereq);
3748 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003749 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003750 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003751 ieoffset = offsetof(struct ieee80211_mgmt,
3752 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003753 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003754
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003755 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003756 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003757 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003758 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003759 } else {
3760 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003761 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003762 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3763 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003764 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003765 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3766 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003767 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003768
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003769 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003770 dev_kfree_skb(wlvif->probereq);
3771 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003772
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003773 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003774 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003775
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003776 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003777 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003778 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003779 wl1271_tx_min_rate_get(wl,
3780 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003781 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003782 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003783 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003784
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003785 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003786 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003787
3788 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003789 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003790 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003791 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003792
3793 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003794 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003795 u32 conf_flags = wl->hw->conf.flags;
3796 /*
3797 * we might have to disable roc, if there was
3798 * no IF_OPER_UP notification.
3799 */
3800 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003801 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003802 if (ret < 0)
3803 goto out;
3804 }
3805 /*
3806 * (we also need to disable roc in case of
3807 * roaming on the same channel. until we will
3808 * have a better flow...)
3809 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003810 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3811 ret = wl12xx_croc(wl,
3812 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003813 if (ret < 0)
3814 goto out;
3815 }
3816
Eliad Peller0603d892011-10-05 11:55:51 +02003817 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003818 if (!(conf_flags & IEEE80211_CONF_IDLE))
3819 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003820 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003821 }
3822 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003823
Eliad Pellerd192d262011-05-24 14:33:08 +03003824 if (changed & BSS_CHANGED_IBSS) {
3825 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3826 bss_conf->ibss_joined);
3827
3828 if (bss_conf->ibss_joined) {
3829 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003830 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003831 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003832 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003833 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003834 wl1271_tx_min_rate_get(wl,
3835 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003836
Shahar Levi06b660e2011-09-05 13:54:36 +03003837 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003838 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3839 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003840 if (ret < 0)
3841 goto out;
3842 }
3843 }
3844
Eliad Peller0603d892011-10-05 11:55:51 +02003845 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003846 if (ret < 0)
3847 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003848
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003849 if (changed & BSS_CHANGED_ARP_FILTER) {
3850 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003851 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003852
Eliad Pellerc5312772010-12-09 11:31:27 +02003853 if (bss_conf->arp_addr_cnt == 1 &&
3854 bss_conf->arp_filter_enabled) {
3855 /*
3856 * The template should have been configured only upon
3857 * association. however, it seems that the correct ip
3858 * isn't being set (when sending), so we have to
3859 * reconfigure the template upon every ip change.
3860 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003861 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003862 if (ret < 0) {
3863 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003864 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003865 }
3866
Eliad Peller0603d892011-10-05 11:55:51 +02003867 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003868 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003869 addr);
3870 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003871 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003872
3873 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003874 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003875 }
3876
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003877 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003878 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003879 if (ret < 0) {
3880 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003881 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003882 }
Eliad Peller251c1772011-08-14 13:17:17 +03003883
3884 /* ROC until connected (after EAPOL exchange) */
3885 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003886 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003887 if (ret < 0)
3888 goto out;
3889
Eliad Pellerba8447f2011-10-10 10:13:00 +02003890 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003891 ieee80211_get_operstate(vif));
3892 }
3893 /*
3894 * stop device role if started (we might already be in
3895 * STA role). TODO: make it better.
3896 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003897 if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) {
Eliad Peller679a6732011-10-11 11:55:44 +02003898 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003899 if (ret < 0)
3900 goto out;
3901 }
Eliad Peller05dba352011-08-23 16:37:01 +03003902
3903 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003904 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3905 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003906 enum wl1271_cmd_ps_mode mode;
3907
3908 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003909 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003910 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003911 true);
3912 if (ret < 0)
3913 goto out;
3914 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003915 }
3916
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003917 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003918 if (sta_exists) {
3919 if ((changed & BSS_CHANGED_HT) &&
3920 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003921 ret = wl1271_acx_set_ht_capabilities(wl,
3922 &sta_ht_cap,
3923 true,
Eliad Peller154da672011-10-05 11:55:53 +02003924 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003925 if (ret < 0) {
3926 wl1271_warning("Set ht cap true failed %d",
3927 ret);
3928 goto out;
3929 }
3930 }
3931 /* handle new association without HT and disassociation */
3932 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003933 ret = wl1271_acx_set_ht_capabilities(wl,
3934 &sta_ht_cap,
3935 false,
Eliad Peller154da672011-10-05 11:55:53 +02003936 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003937 if (ret < 0) {
3938 wl1271_warning("Set ht cap false failed %d",
3939 ret);
3940 goto out;
3941 }
3942 }
3943 }
3944
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003945 /* Handle HT information change. Done after join. */
3946 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003947 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003948 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003949 bss_conf->ht_operation_mode);
3950 if (ret < 0) {
3951 wl1271_warning("Set ht information failed %d", ret);
3952 goto out;
3953 }
3954 }
3955
Arik Nemtsove78a2872010-10-16 19:07:21 +02003956out:
3957 return;
3958}
3959
3960static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3961 struct ieee80211_vif *vif,
3962 struct ieee80211_bss_conf *bss_conf,
3963 u32 changed)
3964{
3965 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003966 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3967 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003968 int ret;
3969
3970 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3971 (int)changed);
3972
3973 mutex_lock(&wl->mutex);
3974
3975 if (unlikely(wl->state == WL1271_STATE_OFF))
3976 goto out;
3977
Eliad Peller10c8cd02011-10-10 10:13:06 +02003978 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3979 goto out;
3980
Ido Yariva6208652011-03-01 15:14:41 +02003981 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003982 if (ret < 0)
3983 goto out;
3984
3985 if (is_ap)
3986 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3987 else
3988 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3989
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003990 wl1271_ps_elp_sleep(wl);
3991
3992out:
3993 mutex_unlock(&wl->mutex);
3994}
3995
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003996static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3997 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003998 const struct ieee80211_tx_queue_params *params)
3999{
4000 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02004001 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02004002 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004003 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02004004
4005 mutex_lock(&wl->mutex);
4006
4007 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
4008
Kalle Valo4695dc92010-03-18 12:26:38 +02004009 if (params->uapsd)
4010 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
4011 else
4012 ps_scheme = CONF_PS_SCHEME_LEGACY;
4013
Arik Nemtsov488fc542010-10-16 20:33:45 +02004014 if (wl->state == WL1271_STATE_OFF) {
4015 /*
4016 * If the state is off, the parameters will be recorded and
4017 * configured on init. This happens in AP-mode.
4018 */
4019 struct conf_tx_ac_category *conf_ac =
4020 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
4021 struct conf_tx_tid *conf_tid =
4022 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
4023
4024 conf_ac->ac = wl1271_tx_get_queue(queue);
4025 conf_ac->cw_min = (u8)params->cw_min;
4026 conf_ac->cw_max = params->cw_max;
4027 conf_ac->aifsn = params->aifs;
4028 conf_ac->tx_op_limit = params->txop << 5;
4029
4030 conf_tid->queue_id = wl1271_tx_get_queue(queue);
4031 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
4032 conf_tid->tsid = wl1271_tx_get_queue(queue);
4033 conf_tid->ps_scheme = ps_scheme;
4034 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
4035 conf_tid->apsd_conf[0] = 0;
4036 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004037 goto out;
4038 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02004039
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004040 ret = wl1271_ps_elp_wakeup(wl);
4041 if (ret < 0)
4042 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004043
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004044 /*
4045 * the txop is confed in units of 32us by the mac80211,
4046 * we need us
4047 */
Eliad Peller0603d892011-10-05 11:55:51 +02004048 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004049 params->cw_min, params->cw_max,
4050 params->aifs, params->txop << 5);
4051 if (ret < 0)
4052 goto out_sleep;
4053
Eliad Peller0603d892011-10-05 11:55:51 +02004054 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004055 CONF_CHANNEL_TYPE_EDCF,
4056 wl1271_tx_get_queue(queue),
4057 ps_scheme, CONF_ACK_POLICY_LEGACY,
4058 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004059
4060out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004061 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004062
4063out:
4064 mutex_unlock(&wl->mutex);
4065
4066 return ret;
4067}
4068
Eliad Peller37a41b42011-09-21 14:06:11 +03004069static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4070 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004071{
4072
4073 struct wl1271 *wl = hw->priv;
4074 u64 mactime = ULLONG_MAX;
4075 int ret;
4076
4077 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4078
4079 mutex_lock(&wl->mutex);
4080
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004081 if (unlikely(wl->state == WL1271_STATE_OFF))
4082 goto out;
4083
Ido Yariva6208652011-03-01 15:14:41 +02004084 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004085 if (ret < 0)
4086 goto out;
4087
4088 ret = wl1271_acx_tsf_info(wl, &mactime);
4089 if (ret < 0)
4090 goto out_sleep;
4091
4092out_sleep:
4093 wl1271_ps_elp_sleep(wl);
4094
4095out:
4096 mutex_unlock(&wl->mutex);
4097 return mactime;
4098}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004099
John W. Linvilleece550d2010-07-28 16:41:06 -04004100static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4101 struct survey_info *survey)
4102{
4103 struct wl1271 *wl = hw->priv;
4104 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004105
John W. Linvilleece550d2010-07-28 16:41:06 -04004106 if (idx != 0)
4107 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004108
John W. Linvilleece550d2010-07-28 16:41:06 -04004109 survey->channel = conf->channel;
4110 survey->filled = SURVEY_INFO_NOISE_DBM;
4111 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004112
John W. Linvilleece550d2010-07-28 16:41:06 -04004113 return 0;
4114}
4115
Arik Nemtsov409622e2011-02-23 00:22:29 +02004116static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004117 struct wl12xx_vif *wlvif,
4118 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004119{
4120 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004121 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004122
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004123
4124 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004125 wl1271_warning("could not allocate HLID - too much stations");
4126 return -EBUSY;
4127 }
4128
4129 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004130 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4131 if (ret < 0) {
4132 wl1271_warning("could not allocate HLID - too many links");
4133 return -EBUSY;
4134 }
4135
4136 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004137 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004138 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004139 return 0;
4140}
4141
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004142void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004143{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004144 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004145 return;
4146
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004147 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004148 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004149 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004150 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004151 __clear_bit(hlid, &wl->ap_ps_map);
4152 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004153 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004154 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004155}
4156
4157static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4158 struct ieee80211_vif *vif,
4159 struct ieee80211_sta *sta)
4160{
4161 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004162 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004163 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004164 int ret = 0;
4165 u8 hlid;
4166
4167 mutex_lock(&wl->mutex);
4168
4169 if (unlikely(wl->state == WL1271_STATE_OFF))
4170 goto out;
4171
Eliad Peller536129c2011-10-05 11:55:45 +02004172 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004173 goto out;
4174
4175 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4176
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004177 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004178 if (ret < 0)
4179 goto out;
4180
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004181 wl_sta = (struct wl1271_station *)sta->drv_priv;
4182 hlid = wl_sta->hlid;
4183
Ido Yariva6208652011-03-01 15:14:41 +02004184 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004185 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004186 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004187
Eliad Peller1b92f152011-10-10 10:13:09 +02004188 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004189 if (ret < 0)
4190 goto out_sleep;
4191
Eliad Pellerb67476e2011-08-14 13:17:23 +03004192 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4193 if (ret < 0)
4194 goto out_sleep;
4195
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004196 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4197 if (ret < 0)
4198 goto out_sleep;
4199
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004200out_sleep:
4201 wl1271_ps_elp_sleep(wl);
4202
Arik Nemtsov409622e2011-02-23 00:22:29 +02004203out_free_sta:
4204 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004205 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004206
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004207out:
4208 mutex_unlock(&wl->mutex);
4209 return ret;
4210}
4211
4212static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4213 struct ieee80211_vif *vif,
4214 struct ieee80211_sta *sta)
4215{
4216 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004217 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004218 struct wl1271_station *wl_sta;
4219 int ret = 0, id;
4220
4221 mutex_lock(&wl->mutex);
4222
4223 if (unlikely(wl->state == WL1271_STATE_OFF))
4224 goto out;
4225
Eliad Peller536129c2011-10-05 11:55:45 +02004226 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004227 goto out;
4228
4229 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4230
4231 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004232 id = wl_sta->hlid;
4233 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004234 goto out;
4235
Ido Yariva6208652011-03-01 15:14:41 +02004236 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004237 if (ret < 0)
4238 goto out;
4239
Eliad Pellerc690ec82011-08-14 13:17:07 +03004240 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004241 if (ret < 0)
4242 goto out_sleep;
4243
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004244 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004245
4246out_sleep:
4247 wl1271_ps_elp_sleep(wl);
4248
4249out:
4250 mutex_unlock(&wl->mutex);
4251 return ret;
4252}
4253
Luciano Coelho4623ec72011-03-21 19:26:41 +02004254static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4255 struct ieee80211_vif *vif,
4256 enum ieee80211_ampdu_mlme_action action,
4257 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4258 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004259{
4260 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004261 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004262 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004263 u8 hlid, *ba_bitmap;
4264
4265 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4266 tid);
4267
4268 /* sanity check - the fields in FW are only 8bits wide */
4269 if (WARN_ON(tid > 0xFF))
4270 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004271
4272 mutex_lock(&wl->mutex);
4273
4274 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4275 ret = -EAGAIN;
4276 goto out;
4277 }
4278
Eliad Peller536129c2011-10-05 11:55:45 +02004279 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004280 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004281 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004282 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004283 struct wl1271_station *wl_sta;
4284
4285 wl_sta = (struct wl1271_station *)sta->drv_priv;
4286 hlid = wl_sta->hlid;
4287 ba_bitmap = &wl->links[hlid].ba_bitmap;
4288 } else {
4289 ret = -EINVAL;
4290 goto out;
4291 }
4292
Ido Yariva6208652011-03-01 15:14:41 +02004293 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004294 if (ret < 0)
4295 goto out;
4296
Shahar Levi70559a02011-05-22 16:10:22 +03004297 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4298 tid, action);
4299
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004300 switch (action) {
4301 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004302 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004303 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004304 break;
4305 }
4306
4307 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4308 ret = -EBUSY;
4309 wl1271_error("exceeded max RX BA sessions");
4310 break;
4311 }
4312
4313 if (*ba_bitmap & BIT(tid)) {
4314 ret = -EINVAL;
4315 wl1271_error("cannot enable RX BA session on active "
4316 "tid: %d", tid);
4317 break;
4318 }
4319
4320 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4321 hlid);
4322 if (!ret) {
4323 *ba_bitmap |= BIT(tid);
4324 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004325 }
4326 break;
4327
4328 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004329 if (!(*ba_bitmap & BIT(tid))) {
4330 ret = -EINVAL;
4331 wl1271_error("no active RX BA session on tid: %d",
4332 tid);
4333 break;
4334 }
4335
4336 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4337 hlid);
4338 if (!ret) {
4339 *ba_bitmap &= ~BIT(tid);
4340 wl->ba_rx_session_count--;
4341 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004342 break;
4343
4344 /*
4345 * The BA initiator session management in FW independently.
4346 * Falling break here on purpose for all TX APDU commands.
4347 */
4348 case IEEE80211_AMPDU_TX_START:
4349 case IEEE80211_AMPDU_TX_STOP:
4350 case IEEE80211_AMPDU_TX_OPERATIONAL:
4351 ret = -EINVAL;
4352 break;
4353
4354 default:
4355 wl1271_error("Incorrect ampdu action id=%x\n", action);
4356 ret = -EINVAL;
4357 }
4358
4359 wl1271_ps_elp_sleep(wl);
4360
4361out:
4362 mutex_unlock(&wl->mutex);
4363
4364 return ret;
4365}
4366
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004367static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4368 struct ieee80211_vif *vif,
4369 const struct cfg80211_bitrate_mask *mask)
4370{
Eliad Peller83587502011-10-10 10:12:53 +02004371 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004372 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004373 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004374
4375 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4376 mask->control[NL80211_BAND_2GHZ].legacy,
4377 mask->control[NL80211_BAND_5GHZ].legacy);
4378
4379 mutex_lock(&wl->mutex);
4380
4381 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004382 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004383 wl1271_tx_enabled_rates_get(wl,
4384 mask->control[i].legacy,
4385 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004386
4387 if (unlikely(wl->state == WL1271_STATE_OFF))
4388 goto out;
4389
4390 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4391 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4392
4393 ret = wl1271_ps_elp_wakeup(wl);
4394 if (ret < 0)
4395 goto out;
4396
4397 wl1271_set_band_rate(wl, wlvif);
4398 wlvif->basic_rate =
4399 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4400 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4401
4402 wl1271_ps_elp_sleep(wl);
4403 }
4404out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004405 mutex_unlock(&wl->mutex);
4406
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004407 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004408}
4409
Shahar Levi6d158ff2011-09-08 13:01:33 +03004410static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4411 struct ieee80211_channel_switch *ch_switch)
4412{
4413 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004414 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004415 int ret;
4416
4417 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4418
4419 mutex_lock(&wl->mutex);
4420
4421 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004422 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4423 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4424 ieee80211_chswitch_done(vif, false);
4425 }
4426 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004427 }
4428
4429 ret = wl1271_ps_elp_wakeup(wl);
4430 if (ret < 0)
4431 goto out;
4432
Eliad Peller52630c52011-10-10 10:13:08 +02004433 /* TODO: change mac80211 to pass vif as param */
4434 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4435 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004436
Eliad Peller52630c52011-10-10 10:13:08 +02004437 if (!ret)
4438 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4439 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004440
4441 wl1271_ps_elp_sleep(wl);
4442
4443out:
4444 mutex_unlock(&wl->mutex);
4445}
4446
Arik Nemtsov33437892011-04-26 23:35:39 +03004447static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4448{
4449 struct wl1271 *wl = hw->priv;
4450 bool ret = false;
4451
4452 mutex_lock(&wl->mutex);
4453
4454 if (unlikely(wl->state == WL1271_STATE_OFF))
4455 goto out;
4456
4457 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004458 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004459out:
4460 mutex_unlock(&wl->mutex);
4461
4462 return ret;
4463}
4464
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004465/* can't be const, mac80211 writes to this */
4466static struct ieee80211_rate wl1271_rates[] = {
4467 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004468 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4469 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004470 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004471 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4472 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004473 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4474 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004475 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4476 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004477 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4478 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004479 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4480 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004481 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4482 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004483 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4484 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004485 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004486 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4487 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004488 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004489 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4490 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004491 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004492 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4493 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004494 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004495 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4496 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004497 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004498 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4499 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004500 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004501 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4502 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004503 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004504 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4505 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004506};
4507
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004508/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004509static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004510 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004511 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004512 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4513 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4514 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004515 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004516 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4517 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4518 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004519 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004520 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4521 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4522 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004523 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004524};
4525
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004526/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004527static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004528 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004529 7, /* CONF_HW_RXTX_RATE_MCS7 */
4530 6, /* CONF_HW_RXTX_RATE_MCS6 */
4531 5, /* CONF_HW_RXTX_RATE_MCS5 */
4532 4, /* CONF_HW_RXTX_RATE_MCS4 */
4533 3, /* CONF_HW_RXTX_RATE_MCS3 */
4534 2, /* CONF_HW_RXTX_RATE_MCS2 */
4535 1, /* CONF_HW_RXTX_RATE_MCS1 */
4536 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004537
4538 11, /* CONF_HW_RXTX_RATE_54 */
4539 10, /* CONF_HW_RXTX_RATE_48 */
4540 9, /* CONF_HW_RXTX_RATE_36 */
4541 8, /* CONF_HW_RXTX_RATE_24 */
4542
4543 /* TI-specific rate */
4544 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4545
4546 7, /* CONF_HW_RXTX_RATE_18 */
4547 6, /* CONF_HW_RXTX_RATE_12 */
4548 3, /* CONF_HW_RXTX_RATE_11 */
4549 5, /* CONF_HW_RXTX_RATE_9 */
4550 4, /* CONF_HW_RXTX_RATE_6 */
4551 2, /* CONF_HW_RXTX_RATE_5_5 */
4552 1, /* CONF_HW_RXTX_RATE_2 */
4553 0 /* CONF_HW_RXTX_RATE_1 */
4554};
4555
Shahar Levie8b03a22010-10-13 16:09:39 +02004556/* 11n STA capabilities */
4557#define HW_RX_HIGHEST_RATE 72
4558
Shahar Levi00d20102010-11-08 11:20:10 +00004559#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004560 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4561 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004562 .ht_supported = true, \
4563 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4564 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4565 .mcs = { \
4566 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4567 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4568 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4569 }, \
4570}
4571
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004572/* can't be const, mac80211 writes to this */
4573static struct ieee80211_supported_band wl1271_band_2ghz = {
4574 .channels = wl1271_channels,
4575 .n_channels = ARRAY_SIZE(wl1271_channels),
4576 .bitrates = wl1271_rates,
4577 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004578 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004579};
4580
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004581/* 5 GHz data rates for WL1273 */
4582static struct ieee80211_rate wl1271_rates_5ghz[] = {
4583 { .bitrate = 60,
4584 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4585 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4586 { .bitrate = 90,
4587 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4588 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4589 { .bitrate = 120,
4590 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4591 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4592 { .bitrate = 180,
4593 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4594 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4595 { .bitrate = 240,
4596 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4597 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4598 { .bitrate = 360,
4599 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4600 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4601 { .bitrate = 480,
4602 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4603 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4604 { .bitrate = 540,
4605 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4606 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4607};
4608
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004609/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004610static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004611 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4612 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4613 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4614 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4615 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4616 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4617 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4618 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4619 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4620 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4621 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4622 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4623 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4624 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4625 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4626 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4627 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4628 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4629 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4630 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4631 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4632 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4633 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4634 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4635 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4636 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4637 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4638 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4639 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4640 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4641 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4642 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4643 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4644 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004645};
4646
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004647/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004648static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004649 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004650 7, /* CONF_HW_RXTX_RATE_MCS7 */
4651 6, /* CONF_HW_RXTX_RATE_MCS6 */
4652 5, /* CONF_HW_RXTX_RATE_MCS5 */
4653 4, /* CONF_HW_RXTX_RATE_MCS4 */
4654 3, /* CONF_HW_RXTX_RATE_MCS3 */
4655 2, /* CONF_HW_RXTX_RATE_MCS2 */
4656 1, /* CONF_HW_RXTX_RATE_MCS1 */
4657 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004658
4659 7, /* CONF_HW_RXTX_RATE_54 */
4660 6, /* CONF_HW_RXTX_RATE_48 */
4661 5, /* CONF_HW_RXTX_RATE_36 */
4662 4, /* CONF_HW_RXTX_RATE_24 */
4663
4664 /* TI-specific rate */
4665 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4666
4667 3, /* CONF_HW_RXTX_RATE_18 */
4668 2, /* CONF_HW_RXTX_RATE_12 */
4669 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4670 1, /* CONF_HW_RXTX_RATE_9 */
4671 0, /* CONF_HW_RXTX_RATE_6 */
4672 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4673 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4674 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4675};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004676
4677static struct ieee80211_supported_band wl1271_band_5ghz = {
4678 .channels = wl1271_channels_5ghz,
4679 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4680 .bitrates = wl1271_rates_5ghz,
4681 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004682 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004683};
4684
Tobias Klausera0ea9492010-05-20 10:38:11 +02004685static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004686 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4687 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4688};
4689
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004690static const struct ieee80211_ops wl1271_ops = {
4691 .start = wl1271_op_start,
4692 .stop = wl1271_op_stop,
4693 .add_interface = wl1271_op_add_interface,
4694 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004695#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004696 .suspend = wl1271_op_suspend,
4697 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004698#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004699 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004700 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004701 .configure_filter = wl1271_op_configure_filter,
4702 .tx = wl1271_op_tx,
4703 .set_key = wl1271_op_set_key,
4704 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004705 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004706 .sched_scan_start = wl1271_op_sched_scan_start,
4707 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004708 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004709 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004710 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004711 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004712 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004713 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004714 .sta_add = wl1271_op_sta_add,
4715 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004716 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004717 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004718 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004719 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004720 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004721};
4722
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004723
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004724u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004725{
4726 u8 idx;
4727
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004728 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004729
4730 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4731 wl1271_error("Illegal RX rate from HW: %d", rate);
4732 return 0;
4733 }
4734
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004735 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004736 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4737 wl1271_error("Unsupported RX rate from HW: %d", rate);
4738 return 0;
4739 }
4740
4741 return idx;
4742}
4743
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004744static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4745 struct device_attribute *attr,
4746 char *buf)
4747{
4748 struct wl1271 *wl = dev_get_drvdata(dev);
4749 ssize_t len;
4750
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004751 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004752
4753 mutex_lock(&wl->mutex);
4754 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4755 wl->sg_enabled);
4756 mutex_unlock(&wl->mutex);
4757
4758 return len;
4759
4760}
4761
4762static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4763 struct device_attribute *attr,
4764 const char *buf, size_t count)
4765{
4766 struct wl1271 *wl = dev_get_drvdata(dev);
4767 unsigned long res;
4768 int ret;
4769
Luciano Coelho6277ed62011-04-01 17:49:54 +03004770 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004771 if (ret < 0) {
4772 wl1271_warning("incorrect value written to bt_coex_mode");
4773 return count;
4774 }
4775
4776 mutex_lock(&wl->mutex);
4777
4778 res = !!res;
4779
4780 if (res == wl->sg_enabled)
4781 goto out;
4782
4783 wl->sg_enabled = res;
4784
4785 if (wl->state == WL1271_STATE_OFF)
4786 goto out;
4787
Ido Yariva6208652011-03-01 15:14:41 +02004788 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004789 if (ret < 0)
4790 goto out;
4791
4792 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4793 wl1271_ps_elp_sleep(wl);
4794
4795 out:
4796 mutex_unlock(&wl->mutex);
4797 return count;
4798}
4799
4800static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4801 wl1271_sysfs_show_bt_coex_state,
4802 wl1271_sysfs_store_bt_coex_state);
4803
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004804static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4805 struct device_attribute *attr,
4806 char *buf)
4807{
4808 struct wl1271 *wl = dev_get_drvdata(dev);
4809 ssize_t len;
4810
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004811 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004812
4813 mutex_lock(&wl->mutex);
4814 if (wl->hw_pg_ver >= 0)
4815 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4816 else
4817 len = snprintf(buf, len, "n/a\n");
4818 mutex_unlock(&wl->mutex);
4819
4820 return len;
4821}
4822
Gery Kahn6f07b722011-07-18 14:21:49 +03004823static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004824 wl1271_sysfs_show_hw_pg_ver, NULL);
4825
Ido Yariv95dac04f2011-06-06 14:57:06 +03004826static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4827 struct bin_attribute *bin_attr,
4828 char *buffer, loff_t pos, size_t count)
4829{
4830 struct device *dev = container_of(kobj, struct device, kobj);
4831 struct wl1271 *wl = dev_get_drvdata(dev);
4832 ssize_t len;
4833 int ret;
4834
4835 ret = mutex_lock_interruptible(&wl->mutex);
4836 if (ret < 0)
4837 return -ERESTARTSYS;
4838
4839 /* Let only one thread read the log at a time, blocking others */
4840 while (wl->fwlog_size == 0) {
4841 DEFINE_WAIT(wait);
4842
4843 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4844 &wait,
4845 TASK_INTERRUPTIBLE);
4846
4847 if (wl->fwlog_size != 0) {
4848 finish_wait(&wl->fwlog_waitq, &wait);
4849 break;
4850 }
4851
4852 mutex_unlock(&wl->mutex);
4853
4854 schedule();
4855 finish_wait(&wl->fwlog_waitq, &wait);
4856
4857 if (signal_pending(current))
4858 return -ERESTARTSYS;
4859
4860 ret = mutex_lock_interruptible(&wl->mutex);
4861 if (ret < 0)
4862 return -ERESTARTSYS;
4863 }
4864
4865 /* Check if the fwlog is still valid */
4866 if (wl->fwlog_size < 0) {
4867 mutex_unlock(&wl->mutex);
4868 return 0;
4869 }
4870
4871 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4872 len = min(count, (size_t)wl->fwlog_size);
4873 wl->fwlog_size -= len;
4874 memcpy(buffer, wl->fwlog, len);
4875
4876 /* Make room for new messages */
4877 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4878
4879 mutex_unlock(&wl->mutex);
4880
4881 return len;
4882}
4883
4884static struct bin_attribute fwlog_attr = {
4885 .attr = {.name = "fwlog", .mode = S_IRUSR},
4886 .read = wl1271_sysfs_read_fwlog,
4887};
4888
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004889static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004890{
4891 int ret;
4892
4893 if (wl->mac80211_registered)
4894 return 0;
4895
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004896 ret = wl1271_fetch_nvs(wl);
4897 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004898 /* NOTE: The wl->nvs->nvs element must be first, in
4899 * order to simplify the casting, we assume it is at
4900 * the beginning of the wl->nvs structure.
4901 */
4902 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004903
4904 wl->mac_addr[0] = nvs_ptr[11];
4905 wl->mac_addr[1] = nvs_ptr[10];
4906 wl->mac_addr[2] = nvs_ptr[6];
4907 wl->mac_addr[3] = nvs_ptr[5];
4908 wl->mac_addr[4] = nvs_ptr[4];
4909 wl->mac_addr[5] = nvs_ptr[3];
4910 }
4911
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004912 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4913
4914 ret = ieee80211_register_hw(wl->hw);
4915 if (ret < 0) {
4916 wl1271_error("unable to register mac80211 hw: %d", ret);
4917 return ret;
4918 }
4919
4920 wl->mac80211_registered = true;
4921
Eliad Pellerd60080a2010-11-24 12:53:16 +02004922 wl1271_debugfs_init(wl);
4923
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004924 register_netdevice_notifier(&wl1271_dev_notifier);
4925
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004926 wl1271_notice("loaded");
4927
4928 return 0;
4929}
4930
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004931static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004932{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004933 if (wl->state == WL1271_STATE_PLT)
4934 __wl1271_plt_stop(wl);
4935
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004936 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004937 ieee80211_unregister_hw(wl->hw);
4938 wl->mac80211_registered = false;
4939
4940}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004941
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004942static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004943{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004944 static const u32 cipher_suites[] = {
4945 WLAN_CIPHER_SUITE_WEP40,
4946 WLAN_CIPHER_SUITE_WEP104,
4947 WLAN_CIPHER_SUITE_TKIP,
4948 WLAN_CIPHER_SUITE_CCMP,
4949 WL1271_CIPHER_SUITE_GEM,
4950 };
4951
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004952 /* The tx descriptor buffer and the TKIP space. */
4953 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4954 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004955
4956 /* unit us */
4957 /* FIXME: find a proper value */
4958 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004959 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004960
4961 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004962 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004963 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004964 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004965 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004966 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004967 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004968 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004969 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004970 IEEE80211_HW_AP_LINK_PS |
4971 IEEE80211_HW_AMPDU_AGGREGATION |
4972 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004973
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004974 wl->hw->wiphy->cipher_suites = cipher_suites;
4975 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4976
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004977 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004978 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4979 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004980 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004981 wl->hw->wiphy->max_sched_scan_ssids = 16;
4982 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004983 /*
4984 * Maximum length of elements in scanning probe request templates
4985 * should be the maximum length possible for a template, without
4986 * the IEEE80211 header of the template
4987 */
Eliad Peller154037d2011-08-14 13:17:12 +03004988 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004989 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004990
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004991 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4992 sizeof(struct ieee80211_header);
4993
Eliad Peller1ec23f72011-08-25 14:26:54 +03004994 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4995
Luciano Coelho4a31c112011-03-21 23:16:14 +02004996 /* make sure all our channels fit in the scanned_ch bitmask */
4997 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4998 ARRAY_SIZE(wl1271_channels_5ghz) >
4999 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005000 /*
5001 * We keep local copies of the band structs because we need to
5002 * modify them on a per-device basis.
5003 */
5004 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
5005 sizeof(wl1271_band_2ghz));
5006 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
5007 sizeof(wl1271_band_5ghz));
5008
5009 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
5010 &wl->bands[IEEE80211_BAND_2GHZ];
5011 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
5012 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005013
Kalle Valo12bd8942010-03-18 12:26:33 +02005014 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02005015 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02005016
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01005017 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
5018
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02005019 /* the FW answers probe-requests in AP-mode */
5020 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
5021 wl->hw->wiphy->probe_resp_offload =
5022 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
5023 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
5024 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
5025
Felipe Balbia390e852011-10-06 10:07:44 +03005026 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005027
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005028 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02005029 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005030
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005031 wl->hw->max_rx_aggregation_subframes = 8;
5032
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005033 return 0;
5034}
5035
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005036#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005037
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005038static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005039{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005040 struct ieee80211_hw *hw;
5041 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005042 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005043 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005044
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005045 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005046
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005047 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5048 if (!hw) {
5049 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005050 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005051 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005052 }
5053
5054 wl = hw->priv;
5055 memset(wl, 0, sizeof(*wl));
5056
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005057 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005058 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005059
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005060 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005061
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005062 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005063 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005064 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5065
Ido Yariva6208652011-03-01 15:14:41 +02005066 skb_queue_head_init(&wl->deferred_rx_queue);
5067 skb_queue_head_init(&wl->deferred_tx_queue);
5068
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005069 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005070 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005071 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5072 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5073 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005074
Eliad Peller92ef8962011-06-07 12:50:46 +03005075 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5076 if (!wl->freezable_wq) {
5077 ret = -ENOMEM;
5078 goto err_hw;
5079 }
5080
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005081 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005082 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005083 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005084 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005085 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005086 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005087 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005088 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005089 wl->ap_ps_map = 0;
5090 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005091 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005092 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005093 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005094 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005095 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005096 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005097 wl->fwlog_size = 0;
5098 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005099
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005100 /* The system link is always allocated */
5101 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5102
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005103 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005104 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005105 wl->tx_frames[i] = NULL;
5106
5107 spin_lock_init(&wl->wl_lock);
5108
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005109 wl->state = WL1271_STATE_OFF;
5110 mutex_init(&wl->mutex);
5111
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005112 /* Apply default driver configuration. */
5113 wl1271_conf_init(wl);
5114
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005115 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5116 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5117 if (!wl->aggr_buf) {
5118 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005119 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005120 }
5121
Ido Yariv990f5de2011-03-31 10:06:59 +02005122 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5123 if (!wl->dummy_packet) {
5124 ret = -ENOMEM;
5125 goto err_aggr;
5126 }
5127
Ido Yariv95dac04f2011-06-06 14:57:06 +03005128 /* Allocate one page for the FW log */
5129 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5130 if (!wl->fwlog) {
5131 ret = -ENOMEM;
5132 goto err_dummy_packet;
5133 }
5134
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005135 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005136
Ido Yariv990f5de2011-03-31 10:06:59 +02005137err_dummy_packet:
5138 dev_kfree_skb(wl->dummy_packet);
5139
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005140err_aggr:
5141 free_pages((unsigned long)wl->aggr_buf, order);
5142
Eliad Peller92ef8962011-06-07 12:50:46 +03005143err_wq:
5144 destroy_workqueue(wl->freezable_wq);
5145
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005146err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005147 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005148 ieee80211_free_hw(hw);
5149
5150err_hw_alloc:
5151
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005152 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005153}
5154
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005155static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005156{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005157 /* Unblock any fwlog readers */
5158 mutex_lock(&wl->mutex);
5159 wl->fwlog_size = -1;
5160 wake_up_interruptible_all(&wl->fwlog_waitq);
5161 mutex_unlock(&wl->mutex);
5162
Felipe Balbif79f8902011-10-06 13:05:25 +03005163 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005164
Felipe Balbif79f8902011-10-06 13:05:25 +03005165 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005166
Felipe Balbif79f8902011-10-06 13:05:25 +03005167 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005168 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005169 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005170 free_pages((unsigned long)wl->aggr_buf,
5171 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005172
5173 wl1271_debugfs_exit(wl);
5174
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005175 vfree(wl->fw);
5176 wl->fw = NULL;
5177 kfree(wl->nvs);
5178 wl->nvs = NULL;
5179
5180 kfree(wl->fw_status);
5181 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005182 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005183
5184 ieee80211_free_hw(wl->hw);
5185
5186 return 0;
5187}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005188
Felipe Balbia390e852011-10-06 10:07:44 +03005189static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5190{
5191 struct wl1271 *wl = cookie;
5192 unsigned long flags;
5193
5194 wl1271_debug(DEBUG_IRQ, "IRQ");
5195
5196 /* complete the ELP completion */
5197 spin_lock_irqsave(&wl->wl_lock, flags);
5198 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5199 if (wl->elp_compl) {
5200 complete(wl->elp_compl);
5201 wl->elp_compl = NULL;
5202 }
5203
5204 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5205 /* don't enqueue a work right now. mark it as pending */
5206 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5207 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5208 disable_irq_nosync(wl->irq);
5209 pm_wakeup_event(wl->dev, 0);
5210 spin_unlock_irqrestore(&wl->wl_lock, flags);
5211 return IRQ_HANDLED;
5212 }
5213 spin_unlock_irqrestore(&wl->wl_lock, flags);
5214
5215 return IRQ_WAKE_THREAD;
5216}
5217
Felipe Balbice2a2172011-10-05 14:12:55 +03005218static int __devinit wl12xx_probe(struct platform_device *pdev)
5219{
Felipe Balbia390e852011-10-06 10:07:44 +03005220 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5221 struct ieee80211_hw *hw;
5222 struct wl1271 *wl;
5223 unsigned long irqflags;
5224 int ret = -ENODEV;
5225
5226 hw = wl1271_alloc_hw();
5227 if (IS_ERR(hw)) {
5228 wl1271_error("can't allocate hw");
5229 ret = PTR_ERR(hw);
5230 goto out;
5231 }
5232
5233 wl = hw->priv;
5234 wl->irq = platform_get_irq(pdev, 0);
5235 wl->ref_clock = pdata->board_ref_clock;
5236 wl->tcxo_clock = pdata->board_tcxo_clock;
5237 wl->platform_quirks = pdata->platform_quirks;
5238 wl->set_power = pdata->set_power;
5239 wl->dev = &pdev->dev;
5240 wl->if_ops = pdata->ops;
5241
5242 platform_set_drvdata(pdev, wl);
5243
5244 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5245 irqflags = IRQF_TRIGGER_RISING;
5246 else
5247 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5248
5249 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5250 irqflags,
5251 pdev->name, wl);
5252 if (ret < 0) {
5253 wl1271_error("request_irq() failed: %d", ret);
5254 goto out_free_hw;
5255 }
5256
5257 ret = enable_irq_wake(wl->irq);
5258 if (!ret) {
5259 wl->irq_wake_enabled = true;
5260 device_init_wakeup(wl->dev, 1);
5261 if (pdata->pwr_in_suspend)
5262 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5263
5264 }
5265 disable_irq(wl->irq);
5266
5267 ret = wl1271_init_ieee80211(wl);
5268 if (ret)
5269 goto out_irq;
5270
5271 ret = wl1271_register_hw(wl);
5272 if (ret)
5273 goto out_irq;
5274
Felipe Balbif79f8902011-10-06 13:05:25 +03005275 /* Create sysfs file to control bt coex state */
5276 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5277 if (ret < 0) {
5278 wl1271_error("failed to create sysfs file bt_coex_state");
5279 goto out_irq;
5280 }
5281
5282 /* Create sysfs file to get HW PG version */
5283 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5284 if (ret < 0) {
5285 wl1271_error("failed to create sysfs file hw_pg_ver");
5286 goto out_bt_coex_state;
5287 }
5288
5289 /* Create sysfs file for the FW log */
5290 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5291 if (ret < 0) {
5292 wl1271_error("failed to create sysfs file fwlog");
5293 goto out_hw_pg_ver;
5294 }
5295
Felipe Balbice2a2172011-10-05 14:12:55 +03005296 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005297
Felipe Balbif79f8902011-10-06 13:05:25 +03005298out_hw_pg_ver:
5299 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5300
5301out_bt_coex_state:
5302 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5303
Felipe Balbia390e852011-10-06 10:07:44 +03005304out_irq:
5305 free_irq(wl->irq, wl);
5306
5307out_free_hw:
5308 wl1271_free_hw(wl);
5309
5310out:
5311 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005312}
5313
5314static int __devexit wl12xx_remove(struct platform_device *pdev)
5315{
Felipe Balbia390e852011-10-06 10:07:44 +03005316 struct wl1271 *wl = platform_get_drvdata(pdev);
5317
5318 if (wl->irq_wake_enabled) {
5319 device_init_wakeup(wl->dev, 0);
5320 disable_irq_wake(wl->irq);
5321 }
5322 wl1271_unregister_hw(wl);
5323 free_irq(wl->irq, wl);
5324 wl1271_free_hw(wl);
5325
Felipe Balbice2a2172011-10-05 14:12:55 +03005326 return 0;
5327}
5328
5329static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005330 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005331 { } /* Terminating Entry */
5332};
5333MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5334
5335static struct platform_driver wl12xx_driver = {
5336 .probe = wl12xx_probe,
5337 .remove = __devexit_p(wl12xx_remove),
5338 .id_table = wl12xx_id_table,
5339 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005340 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005341 .owner = THIS_MODULE,
5342 }
5343};
5344
5345static int __init wl12xx_init(void)
5346{
5347 return platform_driver_register(&wl12xx_driver);
5348}
5349module_init(wl12xx_init);
5350
5351static void __exit wl12xx_exit(void)
5352{
5353 platform_driver_unregister(&wl12xx_driver);
5354}
5355module_exit(wl12xx_exit);
5356
Guy Eilam491bbd62011-01-12 10:33:29 +01005357u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005358EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005359module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005360MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5361
Ido Yariv95dac04f2011-06-06 14:57:06 +03005362module_param_named(fwlog, fwlog_param, charp, 0);
5363MODULE_PARM_DESC(keymap,
5364 "FW logger options: continuous, ondemand, dbgpins or disable");
5365
Eliad Peller2a5bff02011-08-25 18:10:59 +03005366module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5367MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5368
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005369MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005370MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005371MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");