blob: 08fc9d4642884ee1a147095b956d86aca99cc562 [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>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000038#include "reg.h"
39#include "io.h"
40#include "event.h"
41#include "tx.h"
42#include "rx.h"
43#include "ps.h"
44#include "init.h"
45#include "debugfs.h"
46#include "cmd.h"
47#include "boot.h"
48#include "testmode.h"
49#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030050
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020051#define WL1271_BOOT_RETRIES 3
52
Juuso Oikarinen8a080482009-10-13 12:47:44 +030053static struct conf_drv_settings default_conf = {
54 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030055 .params = {
56 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
57 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
58 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
61 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
62 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
64 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
65 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
66 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
68 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
69 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
70 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
71 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
73 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
74 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
75 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
76 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
77 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
78 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
79 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
82 /* active scan params */
83 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
84 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
85 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
86 /* passive scan params */
87 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
88 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
90 /* passive scan in dual antenna params */
91 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
92 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
93 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
94 /* general params */
95 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
96 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
97 [CONF_SG_BEACON_MISS_PERCENT] = 60,
98 [CONF_SG_DHCP_TIME] = 5000,
99 [CONF_SG_RXT] = 1200,
100 [CONF_SG_TXT] = 1000,
101 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
102 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
103 [CONF_SG_HV3_MAX_SERVED] = 6,
104 [CONF_SG_PS_POLL_TIMEOUT] = 10,
105 [CONF_SG_UPSD_TIMEOUT] = 10,
106 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
107 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
108 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
109 /* AP params */
110 [CONF_AP_BEACON_MISS_TX] = 3,
111 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
112 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
113 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
114 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
115 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300116 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200117 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300118 },
119 .rx = {
120 .rx_msdu_life_time = 512000,
121 .packet_detection_threshold = 0,
122 .ps_poll_timeout = 15,
123 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300124 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200125 .rx_cca_threshold = 0,
126 .irq_blk_threshold = 0xFFFF,
127 .irq_pkt_threshold = 0,
128 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300129 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
130 },
131 .tx = {
132 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200133 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300134 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .short_retry_limit = 10,
136 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200137 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300138 },
139 .ac_conf_count = 4,
140 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_BE,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = 3,
146 .tx_op_limit = 0,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_BK,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = 7,
153 .tx_op_limit = 0,
154 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200155 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300156 .ac = CONF_TX_AC_VI,
157 .cw_min = 15,
158 .cw_max = 63,
159 .aifsn = CONF_TX_AIFS_PIFS,
160 .tx_op_limit = 3008,
161 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200162 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300163 .ac = CONF_TX_AC_VO,
164 .cw_min = 15,
165 .cw_max = 63,
166 .aifsn = CONF_TX_AIFS_PIFS,
167 .tx_op_limit = 1504,
168 },
169 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300170 .max_tx_retries = 100,
171 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200172 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300173 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 [CONF_TX_AC_BE] = {
175 .queue_id = CONF_TX_AC_BE,
176 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .tsid = CONF_TX_AC_BE,
178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200182 [CONF_TX_AC_BK] = {
183 .queue_id = CONF_TX_AC_BK,
184 .channel_type = CONF_CHANNEL_TYPE_EDCF,
185 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_VI] = {
191 .queue_id = CONF_TX_AC_VI,
192 .channel_type = CONF_CHANNEL_TYPE_EDCF,
193 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300194 .ps_scheme = CONF_PS_SCHEME_LEGACY,
195 .ack_policy = CONF_ACK_POLICY_LEGACY,
196 .apsd_conf = {0, 0},
197 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200198 [CONF_TX_AC_VO] = {
199 .queue_id = CONF_TX_AC_VO,
200 .channel_type = CONF_CHANNEL_TYPE_EDCF,
201 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300202 .ps_scheme = CONF_PS_SCHEME_LEGACY,
203 .ack_policy = CONF_ACK_POLICY_LEGACY,
204 .apsd_conf = {0, 0},
205 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300206 },
207 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200208 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300209 .tx_compl_threshold = 4,
210 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
211 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200212 .tmpl_short_retry_limit = 10,
213 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300214 },
215 .conn = {
216 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300217 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300219 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_ie = {
221 [0] = {
222 .ie = WLAN_EID_CHANNEL_SWITCH,
223 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300224 },
225 [1] = {
226 .ie = WLAN_EID_HT_INFORMATION,
227 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200230 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 .bss_lose_timeout = 100,
232 .beacon_rx_timeout = 10000,
233 .broadcast_timeout = 20000,
234 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300235 .ps_poll_threshold = 10,
236 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300237 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200238 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300239 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300240 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200241 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300242 .keep_alive_interval = 55000,
243 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300244 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200245 .itrim = {
246 .enable = false,
247 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200248 },
249 .pm_config = {
250 .host_clk_settling_time = 5000,
251 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300252 },
253 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 .trigger_pacing = 1,
255 .avg_weight_rssi_beacon = 20,
256 .avg_weight_rssi_data = 10,
257 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100258 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200259 },
260 .scan = {
261 .min_dwell_time_active = 7500,
262 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100263 .min_dwell_time_passive = 100000,
264 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200265 .num_probe_reqs = 2,
266 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300267 .sched_scan = {
268 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300269 .min_dwell_time_active = 30,
270 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300271 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300272 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .num_probe_reqs = 2,
274 .rssi_threshold = -90,
275 .snr_threshold = 0,
276 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200277 .rf = {
278 .tx_per_channel_power_compensation_2 = {
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 },
281 .tx_per_channel_power_compensation_5 = {
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 },
286 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100287 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300288 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .tx_ba_win_size = 64,
290 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300291 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100292 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200293 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200294 .num_stations = 1,
295 .ssid_profiles = 1,
296 .rx_block_num = 70,
297 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300298 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200299 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200300 .min_req_rx_blocks = 22,
301 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200302 },
303 .mem_wl128x = {
304 .num_stations = 1,
305 .ssid_profiles = 1,
306 .rx_block_num = 40,
307 .tx_min_block_num = 40,
308 .dynamic_memory = 1,
309 .min_req_tx_blocks = 45,
310 .min_req_rx_blocks = 22,
311 .tx_min = 27,
312 },
Shahar Leviff868432011-04-11 15:41:46 +0300313 .fm_coex = {
314 .enable = true,
315 .swallow_period = 5,
316 .n_divider_fref_set_1 = 0xff, /* default */
317 .n_divider_fref_set_2 = 12,
318 .m_divider_fref_set_1 = 148,
319 .m_divider_fref_set_2 = 0xffff, /* default */
320 .coex_pll_stabilization_time = 0xffffffff, /* default */
321 .ldo_stabilization_time = 0xffff, /* default */
322 .fm_disturbed_band_margin = 0xff, /* default */
323 .swallow_clk_diff = 0xff, /* default */
324 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300325 .rx_streaming = {
326 .duration = 150,
327 .queues = 0x1,
328 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300329 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300330 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300331 .fwlog = {
332 .mode = WL12XX_FWLOG_ON_DEMAND,
333 .mem_blocks = 2,
334 .severity = 0,
335 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
336 .output = WL12XX_FWLOG_OUTPUT_HOST,
337 .threshold = 0,
338 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300339 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300340 .rate = {
341 .rate_retry_score = 32000,
342 .per_add = 8192,
343 .per_th1 = 2048,
344 .per_th2 = 4096,
345 .max_per = 8100,
346 .inverse_curiosity_factor = 5,
347 .tx_fail_low_th = 4,
348 .tx_fail_high_th = 10,
349 .per_alpha_shift = 4,
350 .per_add_shift = 13,
351 .per_beta1_shift = 10,
352 .per_beta2_shift = 8,
353 .rate_check_up = 2,
354 .rate_check_down = 12,
355 .rate_retry_policy = {
356 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00,
359 },
360 },
Eliad Peller94877752011-08-28 15:11:56 +0300361 .hangover = {
362 .recover_time = 0,
363 .hangover_period = 20,
364 .dynamic_mode = 1,
365 .early_termination_mode = 1,
366 .max_period = 20,
367 .min_period = 1,
368 .increase_delta = 1,
369 .decrease_delta = 2,
370 .quiet_time = 4,
371 .increase_time = 1,
372 .window_size = 16,
373 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300374};
375
Ido Yariv95dac04f2011-06-06 14:57:06 +0300376static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300377static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300379static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200380 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300381 bool reset_tx_queues);
Eliad Peller170d0e62011-10-05 11:56:06 +0200382static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200383
384
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200385static void wl1271_device_release(struct device *dev)
386{
387
388}
389
390static struct platform_device wl1271_device = {
391 .name = "wl1271",
392 .id = -1,
393
394 /* device model insists to have a release function */
395 .dev = {
396 .release = wl1271_device_release,
397 },
398};
399
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200400static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300401static LIST_HEAD(wl_list);
402
Eliad Pellerba8447f2011-10-10 10:13:00 +0200403static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
404 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300405{
406 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200407
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300408 if (operstate != IF_OPER_UP)
409 return 0;
410
Eliad Peller8181aec2011-10-10 10:13:04 +0200411 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300412 return 0;
413
Eliad Peller154da672011-10-05 11:55:53 +0200414 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300415 if (ret < 0)
416 return ret;
417
Eliad Peller0603d892011-10-05 11:55:51 +0200418 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300419
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300420 wl1271_info("Association completed.");
421 return 0;
422}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300423static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
424 void *arg)
425{
426 struct net_device *dev = arg;
427 struct wireless_dev *wdev;
428 struct wiphy *wiphy;
429 struct ieee80211_hw *hw;
430 struct wl1271 *wl;
431 struct wl1271 *wl_temp;
Eliad Pellerba8447f2011-10-10 10:13:00 +0200432 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300433 int ret = 0;
434
435 /* Check that this notification is for us. */
436 if (what != NETDEV_CHANGE)
437 return NOTIFY_DONE;
438
439 wdev = dev->ieee80211_ptr;
440 if (wdev == NULL)
441 return NOTIFY_DONE;
442
443 wiphy = wdev->wiphy;
444 if (wiphy == NULL)
445 return NOTIFY_DONE;
446
447 hw = wiphy_priv(wiphy);
448 if (hw == NULL)
449 return NOTIFY_DONE;
450
451 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200452 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300453 list_for_each_entry(wl, &wl_list, list) {
454 if (wl == wl_temp)
455 break;
456 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200457 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300458 if (wl != wl_temp)
459 return NOTIFY_DONE;
460
461 mutex_lock(&wl->mutex);
462
463 if (wl->state == WL1271_STATE_OFF)
464 goto out;
465
Eliad Pellerba8447f2011-10-10 10:13:00 +0200466 wl12xx_for_each_wlvif_sta(wl, wlvif) {
467 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
468 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300469
Eliad Pellerba8447f2011-10-10 10:13:00 +0200470 ret = wl1271_ps_elp_wakeup(wl);
471 if (ret < 0)
472 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300473
Eliad Pellerba8447f2011-10-10 10:13:00 +0200474 wl1271_check_operstate(wl, wlvif, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300475
Eliad Pellerba8447f2011-10-10 10:13:00 +0200476 wl1271_ps_elp_sleep(wl);
477 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300478out:
479 mutex_unlock(&wl->mutex);
480
481 return NOTIFY_OK;
482}
483
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100484static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200485 struct regulatory_request *request)
486{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100487 struct ieee80211_supported_band *band;
488 struct ieee80211_channel *ch;
489 int i;
490
491 band = wiphy->bands[IEEE80211_BAND_5GHZ];
492 for (i = 0; i < band->n_channels; i++) {
493 ch = &band->channels[i];
494 if (ch->flags & IEEE80211_CHAN_DISABLED)
495 continue;
496
497 if (ch->flags & IEEE80211_CHAN_RADAR)
498 ch->flags |= IEEE80211_CHAN_NO_IBSS |
499 IEEE80211_CHAN_PASSIVE_SCAN;
500
501 }
502
503 return 0;
504}
505
Eliad Peller9eb599e2011-10-10 10:12:59 +0200506static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
507 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300508{
509 int ret = 0;
510
511 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200512 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300513 if (ret < 0)
514 goto out;
515
516 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200517 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300518 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200519 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300520out:
521 return ret;
522}
523
524/*
525 * this function is being called when the rx_streaming interval
526 * has beed changed or rx_streaming should be disabled
527 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200528int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300529{
530 int ret = 0;
531 int period = wl->conf.rx_streaming.interval;
532
533 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200534 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300535 goto out;
536
537 /* reconfigure/disable according to new streaming_period */
538 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200539 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300540 (wl->conf.rx_streaming.always ||
541 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200542 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300543 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200544 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300545 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200546 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300547 }
548out:
549 return ret;
550}
551
552static void wl1271_rx_streaming_enable_work(struct work_struct *work)
553{
554 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200555 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
556 rx_streaming_enable_work);
557 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300558
559 mutex_lock(&wl->mutex);
560
Eliad Peller0744bdb2011-10-10 10:13:05 +0200561 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200562 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300563 (!wl->conf.rx_streaming.always &&
564 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
565 goto out;
566
567 if (!wl->conf.rx_streaming.interval)
568 goto out;
569
570 ret = wl1271_ps_elp_wakeup(wl);
571 if (ret < 0)
572 goto out;
573
Eliad Peller9eb599e2011-10-10 10:12:59 +0200574 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300575 if (ret < 0)
576 goto out_sleep;
577
578 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200579 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300580 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
581
582out_sleep:
583 wl1271_ps_elp_sleep(wl);
584out:
585 mutex_unlock(&wl->mutex);
586}
587
588static void wl1271_rx_streaming_disable_work(struct work_struct *work)
589{
590 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200591 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
592 rx_streaming_disable_work);
593 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300594
595 mutex_lock(&wl->mutex);
596
Eliad Peller0744bdb2011-10-10 10:13:05 +0200597 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300598 goto out;
599
600 ret = wl1271_ps_elp_wakeup(wl);
601 if (ret < 0)
602 goto out;
603
Eliad Peller9eb599e2011-10-10 10:12:59 +0200604 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300605 if (ret)
606 goto out_sleep;
607
608out_sleep:
609 wl1271_ps_elp_sleep(wl);
610out:
611 mutex_unlock(&wl->mutex);
612}
613
614static void wl1271_rx_streaming_timer(unsigned long data)
615{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200616 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
617 struct wl1271 *wl = wlvif->wl;
618 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300619}
620
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300621static void wl1271_conf_init(struct wl1271 *wl)
622{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300623
624 /*
625 * This function applies the default configuration to the driver. This
626 * function is invoked upon driver load (spi probe.)
627 *
628 * The configuration is stored in a run-time structure in order to
629 * facilitate for run-time adjustment of any of the parameters. Making
630 * changes to the configuration structure will apply the new values on
631 * the next interface up (wl1271_op_start.)
632 */
633
634 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300635 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300636
Ido Yariv95dac04f2011-06-06 14:57:06 +0300637 /* Adjust settings according to optional module parameters */
638 if (fwlog_param) {
639 if (!strcmp(fwlog_param, "continuous")) {
640 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
641 } else if (!strcmp(fwlog_param, "ondemand")) {
642 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
643 } else if (!strcmp(fwlog_param, "dbgpins")) {
644 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
645 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
646 } else if (!strcmp(fwlog_param, "disable")) {
647 wl->conf.fwlog.mem_blocks = 0;
648 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
649 } else {
650 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
651 }
652 }
653}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300654
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300655static int wl1271_plt_init(struct wl1271 *wl)
656{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200657 struct conf_tx_ac_category *conf_ac;
658 struct conf_tx_tid *conf_tid;
659 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300660
Shahar Levi49d750ca2011-03-06 16:32:09 +0200661 if (wl->chip.id == CHIP_ID_1283_PG20)
662 ret = wl128x_cmd_general_parms(wl);
663 else
664 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200665 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200666 return ret;
667
Shahar Levi49d750ca2011-03-06 16:32:09 +0200668 if (wl->chip.id == CHIP_ID_1283_PG20)
669 ret = wl128x_cmd_radio_parms(wl);
670 else
671 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200672 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200673 return ret;
674
Shahar Levi49d750ca2011-03-06 16:32:09 +0200675 if (wl->chip.id != CHIP_ID_1283_PG20) {
676 ret = wl1271_cmd_ext_radio_parms(wl);
677 if (ret < 0)
678 return ret;
679 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200680 if (ret < 0)
681 return ret;
682
Shahar Levi48a61472011-03-06 16:32:08 +0200683 /* Chip-specific initializations */
684 ret = wl1271_chip_specific_init(wl);
685 if (ret < 0)
686 return ret;
687
Eliad Peller92c77c72011-10-05 11:55:40 +0200688 ret = wl1271_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200689 if (ret < 0)
690 return ret;
691
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300692 ret = wl1271_acx_init_mem_config(wl);
693 if (ret < 0)
694 return ret;
695
Luciano Coelho12419cc2010-02-18 13:25:44 +0200696 /* PHY layer config */
697 ret = wl1271_init_phy_config(wl);
698 if (ret < 0)
699 goto out_free_memmap;
700
701 ret = wl1271_acx_dco_itrim_params(wl);
702 if (ret < 0)
703 goto out_free_memmap;
704
705 /* Initialize connection monitoring thresholds */
Eliad Peller0603d892011-10-05 11:55:51 +0200706 ret = wl1271_acx_conn_monit_params(wl, NULL, false); /* TODO: fix */
Luciano Coelho12419cc2010-02-18 13:25:44 +0200707 if (ret < 0)
708 goto out_free_memmap;
709
710 /* Bluetooth WLAN coexistence */
711 ret = wl1271_init_pta(wl);
712 if (ret < 0)
713 goto out_free_memmap;
714
Shahar Leviff868432011-04-11 15:41:46 +0300715 /* FM WLAN coexistence */
716 ret = wl1271_acx_fm_coex(wl);
717 if (ret < 0)
718 goto out_free_memmap;
719
Luciano Coelho12419cc2010-02-18 13:25:44 +0200720 /* Energy detection */
721 ret = wl1271_init_energy_detection(wl);
722 if (ret < 0)
723 goto out_free_memmap;
724
Eliad Peller7f0979882011-08-14 13:17:06 +0300725 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600726 if (ret < 0)
727 goto out_free_memmap;
728
Luciano Coelho12419cc2010-02-18 13:25:44 +0200729 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100730 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200731 if (ret < 0)
732 goto out_free_memmap;
733
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200734 /* Default TID/AC configuration */
735 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200736 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200737 conf_ac = &wl->conf.tx.ac_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200738 /* TODO: fix */
739 ret = wl1271_acx_ac_cfg(wl, NULL, conf_ac->ac, conf_ac->cw_min,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200740 conf_ac->cw_max, conf_ac->aifsn,
741 conf_ac->tx_op_limit);
742 if (ret < 0)
743 goto out_free_memmap;
744
Luciano Coelho12419cc2010-02-18 13:25:44 +0200745 conf_tid = &wl->conf.tx.tid_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200746 /* TODO: fix */
747 ret = wl1271_acx_tid_cfg(wl, NULL, conf_tid->queue_id,
Luciano Coelho12419cc2010-02-18 13:25:44 +0200748 conf_tid->channel_type,
749 conf_tid->tsid,
750 conf_tid->ps_scheme,
751 conf_tid->ack_policy,
752 conf_tid->apsd_conf[0],
753 conf_tid->apsd_conf[1]);
754 if (ret < 0)
755 goto out_free_memmap;
756 }
757
Luciano Coelho12419cc2010-02-18 13:25:44 +0200758 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200759 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300760 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200761 goto out_free_memmap;
762
763 /* Configure for CAM power saving (ie. always active) */
764 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
765 if (ret < 0)
766 goto out_free_memmap;
767
768 /* configure PM */
769 ret = wl1271_acx_pm_config(wl);
770 if (ret < 0)
771 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300772
773 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200774
775 out_free_memmap:
776 kfree(wl->target_mem_map);
777 wl->target_mem_map = NULL;
778
779 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300780}
781
Eliad Peller6e8cd332011-10-10 10:13:13 +0200782static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
783 struct wl12xx_vif *wlvif,
784 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200785{
Arik Nemtsovda032092011-08-25 12:43:15 +0300786 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200787
Arik Nemtsovb622d992011-02-23 00:22:31 +0200788 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300789 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200790
791 /*
792 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300793 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200794 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300795 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200796 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200797
Arik Nemtsovda032092011-08-25 12:43:15 +0300798 /*
799 * Start high-level PS if the STA is asleep with enough blocks in FW.
800 * Make an exception if this is the only connected station. In this
801 * case FW-memory congestion is not a problem.
802 */
803 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200804 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200805}
806
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300807static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200808 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300809 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200810{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200811 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200812 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300813 u8 hlid, cnt;
814
815 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200816
817 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
818 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
819 wl1271_debug(DEBUG_PSM,
820 "link ps prev 0x%x cur 0x%x changed 0x%x",
821 wl->ap_fw_ps_map, cur_fw_ps_map,
822 wl->ap_fw_ps_map ^ cur_fw_ps_map);
823
824 wl->ap_fw_ps_map = cur_fw_ps_map;
825 }
826
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200827 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
828 lnk = &wl->links[hlid];
829 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200830
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200831 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
832 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200833
Eliad Peller6e8cd332011-10-10 10:13:13 +0200834 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
835 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200836 }
837}
838
Eliad Peller4d56ad92011-08-14 13:17:05 +0300839static void wl12xx_fw_status(struct wl1271 *wl,
840 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300841{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200842 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200843 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200844 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300845 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300846 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300847
Eliad Peller4d56ad92011-08-14 13:17:05 +0300848 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200849
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300850 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
851 "drv_rx_counter = %d, tx_results_counter = %d)",
852 status->intr,
853 status->fw_rx_counter,
854 status->drv_rx_counter,
855 status->tx_results_counter);
856
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300857 for (i = 0; i < NUM_TX_QUEUES; i++) {
858 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300859 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300860 (status->tx_released_pkts[i] -
861 wl->tx_pkts_freed[i]) & 0xff;
862
863 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
864 }
865
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300866 /* prevent wrap-around in total blocks counter */
867 if (likely(wl->tx_blocks_freed <=
868 le32_to_cpu(status->total_released_blks)))
869 freed_blocks = le32_to_cpu(status->total_released_blks) -
870 wl->tx_blocks_freed;
871 else
872 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
873 le32_to_cpu(status->total_released_blks);
874
Eliad Peller4d56ad92011-08-14 13:17:05 +0300875 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200876
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300877 wl->tx_allocated_blocks -= freed_blocks;
878
Eliad Peller4d56ad92011-08-14 13:17:05 +0300879 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200880
Eliad Peller4d56ad92011-08-14 13:17:05 +0300881 /*
882 * The FW might change the total number of TX memblocks before
883 * we get a notification about blocks being released. Thus, the
884 * available blocks calculation might yield a temporary result
885 * which is lower than the actual available blocks. Keeping in
886 * mind that only blocks that were allocated can be moved from
887 * TX to RX, tx_blocks_available should never decrease here.
888 */
889 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
890 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300891
Ido Yariva5225502010-10-12 14:49:10 +0200892 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200893 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200894 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300895
Eliad Peller4d56ad92011-08-14 13:17:05 +0300896 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200897 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200898 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200899 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300900
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300901 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200902 getnstimeofday(&ts);
903 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
904 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300905}
906
Ido Yariva6208652011-03-01 15:14:41 +0200907static void wl1271_flush_deferred_work(struct wl1271 *wl)
908{
909 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200910
Ido Yariva6208652011-03-01 15:14:41 +0200911 /* Pass all received frames to the network stack */
912 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
913 ieee80211_rx_ni(wl->hw, skb);
914
915 /* Return sent skbs to the network stack */
916 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300917 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200918}
919
920static void wl1271_netstack_work(struct work_struct *work)
921{
922 struct wl1271 *wl =
923 container_of(work, struct wl1271, netstack_work);
924
925 do {
926 wl1271_flush_deferred_work(wl);
927 } while (skb_queue_len(&wl->deferred_rx_queue));
928}
929
930#define WL1271_IRQ_MAX_LOOPS 256
931
932irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300933{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300934 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300935 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200936 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200937 struct wl1271 *wl = (struct wl1271 *)cookie;
938 bool done = false;
939 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200940 unsigned long flags;
941
942 /* TX might be handled here, avoid redundant work */
943 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
944 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945
Ido Yariv341b7cd2011-03-31 10:07:01 +0200946 /*
947 * In case edge triggered interrupt must be used, we cannot iterate
948 * more than once without introducing race conditions with the hardirq.
949 */
950 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
951 loopcount = 1;
952
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300953 mutex_lock(&wl->mutex);
954
955 wl1271_debug(DEBUG_IRQ, "IRQ work");
956
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200957 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300958 goto out;
959
Ido Yariva6208652011-03-01 15:14:41 +0200960 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300961 if (ret < 0)
962 goto out;
963
Ido Yariva6208652011-03-01 15:14:41 +0200964 while (!done && loopcount--) {
965 /*
966 * In order to avoid a race with the hardirq, clear the flag
967 * before acknowledging the chip. Since the mutex is held,
968 * wl1271_ps_elp_wakeup cannot be called concurrently.
969 */
970 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
971 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200972
Eliad Peller4d56ad92011-08-14 13:17:05 +0300973 wl12xx_fw_status(wl, wl->fw_status);
974 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200975 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200976 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200977 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200978 continue;
979 }
980
Eliad Pellerccc83b02010-10-27 14:09:57 +0200981 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
982 wl1271_error("watchdog interrupt received! "
983 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300984 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200985
986 /* restarting the chip. ignore any other interrupt. */
987 goto out;
988 }
989
Ido Yariva6208652011-03-01 15:14:41 +0200990 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200991 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
992
Eliad Peller4d56ad92011-08-14 13:17:05 +0300993 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200994
Ido Yariva5225502010-10-12 14:49:10 +0200995 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200996 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200997 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300998 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200999 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001000 /*
1001 * In order to avoid starvation of the TX path,
1002 * call the work function directly.
1003 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001004 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +02001005 } else {
1006 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001007 }
1008
Ido Yariv8aad2462011-03-01 15:14:38 +02001009 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001010 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +02001011 (wl->tx_results_count & 0xff))
1012 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001013
1014 /* Make sure the deferred queues don't get too long */
1015 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1016 skb_queue_len(&wl->deferred_rx_queue);
1017 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1018 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001019 }
1020
1021 if (intr & WL1271_ACX_INTR_EVENT_A) {
1022 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1023 wl1271_event_handle(wl, 0);
1024 }
1025
1026 if (intr & WL1271_ACX_INTR_EVENT_B) {
1027 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1028 wl1271_event_handle(wl, 1);
1029 }
1030
1031 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1032 wl1271_debug(DEBUG_IRQ,
1033 "WL1271_ACX_INTR_INIT_COMPLETE");
1034
1035 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1036 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 }
1038
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039 wl1271_ps_elp_sleep(wl);
1040
1041out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001042 spin_lock_irqsave(&wl->wl_lock, flags);
1043 /* In case TX was not handled here, queue TX work */
1044 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1045 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001046 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001047 ieee80211_queue_work(wl->hw, &wl->tx_work);
1048 spin_unlock_irqrestore(&wl->wl_lock, flags);
1049
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001051
1052 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053}
Ido Yariva6208652011-03-01 15:14:41 +02001054EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056static int wl1271_fetch_firmware(struct wl1271 *wl)
1057{
1058 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001059 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001060 int ret;
1061
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001062 if (wl->chip.id == CHIP_ID_1283_PG20)
1063 fw_name = WL128X_FW_NAME;
1064 else
1065 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001066
1067 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1068
1069 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001070
1071 if (ret < 0) {
1072 wl1271_error("could not get firmware: %d", ret);
1073 return ret;
1074 }
1075
1076 if (fw->size % 4) {
1077 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1078 fw->size);
1079 ret = -EILSEQ;
1080 goto out;
1081 }
1082
Arik Nemtsov166d5042010-10-16 21:44:57 +02001083 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001085 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001086
1087 if (!wl->fw) {
1088 wl1271_error("could not allocate memory for the firmware");
1089 ret = -ENOMEM;
1090 goto out;
1091 }
1092
1093 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001094 ret = 0;
1095
1096out:
1097 release_firmware(fw);
1098
1099 return ret;
1100}
1101
1102static int wl1271_fetch_nvs(struct wl1271 *wl)
1103{
1104 const struct firmware *fw;
1105 int ret;
1106
Shahar Levi5aa42342011-03-06 16:32:07 +02001107 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001108
1109 if (ret < 0) {
1110 wl1271_error("could not get nvs file: %d", ret);
1111 return ret;
1112 }
1113
Shahar Levibc765bf2011-03-06 16:32:10 +02001114 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001115
1116 if (!wl->nvs) {
1117 wl1271_error("could not allocate memory for the nvs file");
1118 ret = -ENOMEM;
1119 goto out;
1120 }
1121
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001122 wl->nvs_len = fw->size;
1123
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001124out:
1125 release_firmware(fw);
1126
1127 return ret;
1128}
1129
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001130void wl12xx_queue_recovery_work(struct wl1271 *wl)
1131{
1132 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1133 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1134}
1135
Ido Yariv95dac04f2011-06-06 14:57:06 +03001136size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1137{
1138 size_t len = 0;
1139
1140 /* The FW log is a length-value list, find where the log end */
1141 while (len < maxlen) {
1142 if (memblock[len] == 0)
1143 break;
1144 if (len + memblock[len] + 1 > maxlen)
1145 break;
1146 len += memblock[len] + 1;
1147 }
1148
1149 /* Make sure we have enough room */
1150 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1151
1152 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1153 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1154 wl->fwlog_size += len;
1155
1156 return len;
1157}
1158
1159static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1160{
1161 u32 addr;
1162 u32 first_addr;
1163 u8 *block;
1164
1165 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1166 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1167 (wl->conf.fwlog.mem_blocks == 0))
1168 return;
1169
1170 wl1271_info("Reading FW panic log");
1171
1172 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1173 if (!block)
1174 return;
1175
1176 /*
1177 * Make sure the chip is awake and the logger isn't active.
1178 * This might fail if the firmware hanged.
1179 */
1180 if (!wl1271_ps_elp_wakeup(wl))
1181 wl12xx_cmd_stop_fwlog(wl);
1182
1183 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001184 wl12xx_fw_status(wl, wl->fw_status);
1185 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001186 if (!first_addr)
1187 goto out;
1188
1189 /* Traverse the memory blocks linked list */
1190 addr = first_addr;
1191 do {
1192 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1193 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1194 false);
1195
1196 /*
1197 * Memory blocks are linked to one another. The first 4 bytes
1198 * of each memory block hold the hardware address of the next
1199 * one. The last memory block points to the first one.
1200 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001201 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001202 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1203 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1204 break;
1205 } while (addr && (addr != first_addr));
1206
1207 wake_up_interruptible(&wl->fwlog_waitq);
1208
1209out:
1210 kfree(block);
1211}
1212
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001213static void wl1271_recovery_work(struct work_struct *work)
1214{
1215 struct wl1271 *wl =
1216 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001217 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001218 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001219
1220 mutex_lock(&wl->mutex);
1221
1222 if (wl->state != WL1271_STATE_ON)
1223 goto out;
1224
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001225 /* Avoid a recursive recovery */
1226 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1227
Ido Yariv95dac04f2011-06-06 14:57:06 +03001228 wl12xx_read_fwlog_panic(wl);
1229
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001230 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1231 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001232
Eliad Peller2a5bff02011-08-25 18:10:59 +03001233 BUG_ON(bug_on_recovery);
1234
Oz Krakowskib992c682011-06-26 10:36:02 +03001235 /*
1236 * Advance security sequence number to overcome potential progress
1237 * in the firmware during recovery. This doens't hurt if the network is
1238 * not encrypted.
1239 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001240 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001241 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001242 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001243 wlvif->tx_security_seq +=
1244 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1245 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001246
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001247 /* Prevent spurious TX during FW restart */
1248 ieee80211_stop_queues(wl->hw);
1249
Luciano Coelho33c2c062011-05-10 14:46:02 +03001250 if (wl->sched_scanning) {
1251 ieee80211_sched_scan_stopped(wl->hw);
1252 wl->sched_scanning = false;
1253 }
1254
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001255 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001256 while (!list_empty(&wl->wlvif_list)) {
1257 wlvif = list_first_entry(&wl->wlvif_list,
1258 struct wl12xx_vif, list);
1259 vif = wl12xx_wlvif_to_vif(wlvif);
1260 __wl1271_op_remove_interface(wl, vif, false);
1261 }
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001262
1263 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1264
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001265 ieee80211_restart_hw(wl->hw);
1266
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001267 /*
1268 * Its safe to enable TX now - the queues are stopped after a request
1269 * to restart the HW.
1270 */
1271 ieee80211_wake_queues(wl->hw);
1272
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001273out:
1274 mutex_unlock(&wl->mutex);
1275}
1276
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001277static void wl1271_fw_wakeup(struct wl1271 *wl)
1278{
1279 u32 elp_reg;
1280
1281 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001282 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283}
1284
1285static int wl1271_setup(struct wl1271 *wl)
1286{
1287 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1288 if (!wl->fw_status)
1289 return -ENOMEM;
1290
1291 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1292 if (!wl->tx_res_if) {
1293 kfree(wl->fw_status);
1294 return -ENOMEM;
1295 }
1296
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001297 return 0;
1298}
1299
1300static int wl1271_chip_wakeup(struct wl1271 *wl)
1301{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001302 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001303 int ret = 0;
1304
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001305 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001306 ret = wl1271_power_on(wl);
1307 if (ret < 0)
1308 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001309 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001310 wl1271_io_reset(wl);
1311 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001312
1313 /* We don't need a real memory partition here, because we only want
1314 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001315 memset(&partition, 0, sizeof(partition));
1316 partition.reg.start = REGISTERS_BASE;
1317 partition.reg.size = REGISTERS_DOWN_SIZE;
1318 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001319
1320 /* ELP module wake up */
1321 wl1271_fw_wakeup(wl);
1322
1323 /* whal_FwCtrl_BootSm() */
1324
1325 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001326 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327
1328 /* 1. check if chip id is valid */
1329
1330 switch (wl->chip.id) {
1331 case CHIP_ID_1271_PG10:
1332 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1333 wl->chip.id);
1334
1335 ret = wl1271_setup(wl);
1336 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001337 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001338 break;
1339 case CHIP_ID_1271_PG20:
1340 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1341 wl->chip.id);
1342
1343 ret = wl1271_setup(wl);
1344 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001345 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001346 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001347 case CHIP_ID_1283_PG20:
1348 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1349 wl->chip.id);
1350
1351 ret = wl1271_setup(wl);
1352 if (ret < 0)
1353 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001354
Ido Yariv0da13da2011-03-31 10:06:58 +02001355 if (wl1271_set_block_size(wl))
1356 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001357 break;
1358 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001360 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001361 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001362 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001363 }
1364
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001365 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001366 ret = wl1271_fetch_firmware(wl);
1367 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001368 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001369 }
1370
1371 /* No NVS from netlink, try to get it from the filesystem */
1372 if (wl->nvs == NULL) {
1373 ret = wl1271_fetch_nvs(wl);
1374 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001375 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001376 }
1377
1378out:
1379 return ret;
1380}
1381
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382int wl1271_plt_start(struct wl1271 *wl)
1383{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001384 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001385 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001386 int ret;
1387
1388 mutex_lock(&wl->mutex);
1389
1390 wl1271_notice("power up");
1391
1392 if (wl->state != WL1271_STATE_OFF) {
1393 wl1271_error("cannot go into PLT state because not "
1394 "in off state: %d", wl->state);
1395 ret = -EBUSY;
1396 goto out;
1397 }
1398
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001399 while (retries) {
1400 retries--;
1401 ret = wl1271_chip_wakeup(wl);
1402 if (ret < 0)
1403 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001404
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001405 ret = wl1271_boot(wl);
1406 if (ret < 0)
1407 goto power_off;
1408
1409 ret = wl1271_plt_init(wl);
1410 if (ret < 0)
1411 goto irq_disable;
1412
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001413 wl->state = WL1271_STATE_PLT;
1414 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001415 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001416
Gery Kahn6f07b722011-07-18 14:21:49 +03001417 /* update hw/fw version info in wiphy struct */
1418 wiphy->hw_version = wl->chip.id;
1419 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1420 sizeof(wiphy->fw_version));
1421
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001422 goto out;
1423
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001424irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001425 mutex_unlock(&wl->mutex);
1426 /* Unlocking the mutex in the middle of handling is
1427 inherently unsafe. In this case we deem it safe to do,
1428 because we need to let any possibly pending IRQ out of
1429 the system (and while we are WL1271_STATE_OFF the IRQ
1430 work function will not do anything.) Also, any other
1431 possible concurrent operations will fail due to the
1432 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001433 wl1271_disable_interrupts(wl);
1434 wl1271_flush_deferred_work(wl);
1435 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001436 mutex_lock(&wl->mutex);
1437power_off:
1438 wl1271_power_off(wl);
1439 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001440
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001441 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1442 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001443out:
1444 mutex_unlock(&wl->mutex);
1445
1446 return ret;
1447}
1448
Luciano Coelho4623ec72011-03-21 19:26:41 +02001449static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001450{
1451 int ret = 0;
1452
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001453 wl1271_notice("power down");
1454
1455 if (wl->state != WL1271_STATE_PLT) {
1456 wl1271_error("cannot power down because not in PLT "
1457 "state: %d", wl->state);
1458 ret = -EBUSY;
1459 goto out;
1460 }
1461
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001462 wl1271_power_off(wl);
1463
1464 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001465 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001466
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001467 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001468 wl1271_disable_interrupts(wl);
1469 wl1271_flush_deferred_work(wl);
1470 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001471 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001472 mutex_lock(&wl->mutex);
1473out:
1474 return ret;
1475}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001476
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001477int wl1271_plt_stop(struct wl1271 *wl)
1478{
1479 int ret;
1480
1481 mutex_lock(&wl->mutex);
1482 ret = __wl1271_plt_stop(wl);
1483 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001484 return ret;
1485}
1486
Johannes Berg7bb45682011-02-24 14:42:06 +01001487static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001488{
1489 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001490 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1491 struct ieee80211_vif *vif = info->control.vif;
1492 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001493 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001494 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001495 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001496
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001497 mapping = skb_get_queue_mapping(skb);
1498 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001499
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001500 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001501
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001502 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001503
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001504 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001505 if (hlid == WL12XX_INVALID_LINK_ID ||
1506 !test_bit(hlid, wlvif->links_map)) {
1507 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
1508 dev_kfree_skb(skb);
1509 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001510 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001511
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001512 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1513 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1514
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001515 wl->tx_queue_count[q]++;
1516
1517 /*
1518 * The workqueue is slow to process the tx_queue and we need stop
1519 * the queue here, otherwise the queue will get too long.
1520 */
1521 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1522 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1523 ieee80211_stop_queue(wl->hw, mapping);
1524 set_bit(q, &wl->stopped_queues_map);
1525 }
1526
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001527 /*
1528 * The chip specific setup must run before the first TX packet -
1529 * before that, the tx_work will not be initialized!
1530 */
1531
Ido Yarivb07d4032011-03-01 15:14:43 +02001532 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1533 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001534 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001535
Arik Nemtsov04216da2011-08-14 13:17:38 +03001536out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001537 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001538}
1539
Shahar Leviae47c452011-03-06 16:32:14 +02001540int wl1271_tx_dummy_packet(struct wl1271 *wl)
1541{
Ido Yariv990f5de2011-03-31 10:06:59 +02001542 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001543 int q;
1544
1545 /* no need to queue a new dummy packet if one is already pending */
1546 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1547 return 0;
1548
1549 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001550
Ido Yariv990f5de2011-03-31 10:06:59 +02001551 spin_lock_irqsave(&wl->wl_lock, flags);
1552 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001553 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001554 spin_unlock_irqrestore(&wl->wl_lock, flags);
1555
1556 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1557 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001558 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001559
1560 /*
1561 * If the FW TX is busy, TX work will be scheduled by the threaded
1562 * interrupt handler function
1563 */
1564 return 0;
1565}
1566
1567/*
1568 * The size of the dummy packet should be at least 1400 bytes. However, in
1569 * order to minimize the number of bus transactions, aligning it to 512 bytes
1570 * boundaries could be beneficial, performance wise
1571 */
1572#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1573
Luciano Coelhocf27d862011-04-01 21:08:23 +03001574static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001575{
1576 struct sk_buff *skb;
1577 struct ieee80211_hdr_3addr *hdr;
1578 unsigned int dummy_packet_size;
1579
1580 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1581 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1582
1583 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001584 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001585 wl1271_warning("Failed to allocate a dummy packet skb");
1586 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001587 }
1588
1589 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1590
1591 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1592 memset(hdr, 0, sizeof(*hdr));
1593 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001594 IEEE80211_STYPE_NULLFUNC |
1595 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001596
Ido Yariv990f5de2011-03-31 10:06:59 +02001597 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001598
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001599 /* Dummy packets require the TID to be management */
1600 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001601
1602 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001603 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001604 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001605
Ido Yariv990f5de2011-03-31 10:06:59 +02001606 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001607}
1608
Ido Yariv990f5de2011-03-31 10:06:59 +02001609
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001610static struct notifier_block wl1271_dev_notifier = {
1611 .notifier_call = wl1271_dev_notify,
1612};
1613
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001614#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001615static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1616 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001617{
Eliad Pellere85d1622011-06-27 13:06:43 +03001618 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001619
Eliad Peller94390642011-05-13 11:57:13 +03001620 mutex_lock(&wl->mutex);
1621
Eliad Pellerba8447f2011-10-10 10:13:00 +02001622 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001623 goto out_unlock;
1624
Eliad Peller94390642011-05-13 11:57:13 +03001625 ret = wl1271_ps_elp_wakeup(wl);
1626 if (ret < 0)
1627 goto out_unlock;
1628
1629 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001630 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001631 DECLARE_COMPLETION_ONSTACK(compl);
1632
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001633 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001634 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001635 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001636 if (ret < 0)
1637 goto out_sleep;
1638
1639 /* we must unlock here so we will be able to get events */
1640 wl1271_ps_elp_sleep(wl);
1641 mutex_unlock(&wl->mutex);
1642
1643 ret = wait_for_completion_timeout(
1644 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1645 if (ret <= 0) {
1646 wl1271_warning("couldn't enter ps mode!");
1647 ret = -EBUSY;
1648 goto out;
1649 }
1650
1651 /* take mutex again, and wakeup */
1652 mutex_lock(&wl->mutex);
1653
1654 ret = wl1271_ps_elp_wakeup(wl);
1655 if (ret < 0)
1656 goto out_unlock;
1657 }
1658out_sleep:
1659 wl1271_ps_elp_sleep(wl);
1660out_unlock:
1661 mutex_unlock(&wl->mutex);
1662out:
1663 return ret;
1664
1665}
1666
Eliad Peller0603d892011-10-05 11:55:51 +02001667static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1668 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001669{
Eliad Pellere85d1622011-06-27 13:06:43 +03001670 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001671
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001672 mutex_lock(&wl->mutex);
1673
Eliad Peller53d40d02011-10-10 10:13:02 +02001674 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001675 goto out_unlock;
1676
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001677 ret = wl1271_ps_elp_wakeup(wl);
1678 if (ret < 0)
1679 goto out_unlock;
1680
Eliad Peller0603d892011-10-05 11:55:51 +02001681 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001682
1683 wl1271_ps_elp_sleep(wl);
1684out_unlock:
1685 mutex_unlock(&wl->mutex);
1686 return ret;
1687
1688}
1689
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001690static int wl1271_configure_suspend(struct wl1271 *wl,
1691 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001692{
Eliad Peller536129c2011-10-05 11:55:45 +02001693 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001694 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001695 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001696 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001697 return 0;
1698}
1699
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001700static void wl1271_configure_resume(struct wl1271 *wl,
1701 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001702{
1703 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001704 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1705 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001706
1707 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001708 return;
1709
1710 mutex_lock(&wl->mutex);
1711 ret = wl1271_ps_elp_wakeup(wl);
1712 if (ret < 0)
1713 goto out;
1714
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001715 if (is_sta) {
1716 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001717 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001718 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001719 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001720 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001721 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001722 }
Eliad Peller94390642011-05-13 11:57:13 +03001723
1724 wl1271_ps_elp_sleep(wl);
1725out:
1726 mutex_unlock(&wl->mutex);
1727}
1728
Eliad Peller402e48612011-05-13 11:57:09 +03001729static int wl1271_op_suspend(struct ieee80211_hw *hw,
1730 struct cfg80211_wowlan *wow)
1731{
1732 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001733 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001734 int ret;
1735
Eliad Peller402e48612011-05-13 11:57:09 +03001736 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001737 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001738
Eliad Peller4a859df2011-06-06 12:21:52 +03001739 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001740 wl12xx_for_each_wlvif(wl, wlvif) {
1741 ret = wl1271_configure_suspend(wl, wlvif);
1742 if (ret < 0) {
1743 wl1271_warning("couldn't prepare device to suspend");
1744 return ret;
1745 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001746 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001747 /* flush any remaining work */
1748 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001749
1750 /*
1751 * disable and re-enable interrupts in order to flush
1752 * the threaded_irq
1753 */
1754 wl1271_disable_interrupts(wl);
1755
1756 /*
1757 * set suspended flag to avoid triggering a new threaded_irq
1758 * work. no need for spinlock as interrupts are disabled.
1759 */
1760 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1761
1762 wl1271_enable_interrupts(wl);
1763 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001764 wl12xx_for_each_wlvif(wl, wlvif) {
1765 flush_delayed_work(&wlvif->pspoll_work);
1766 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001767 flush_delayed_work(&wl->elp_work);
1768
Eliad Peller402e48612011-05-13 11:57:09 +03001769 return 0;
1770}
1771
1772static int wl1271_op_resume(struct ieee80211_hw *hw)
1773{
1774 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001775 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001776 unsigned long flags;
1777 bool run_irq_work = false;
1778
Eliad Peller402e48612011-05-13 11:57:09 +03001779 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1780 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001781 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001782
1783 /*
1784 * re-enable irq_work enqueuing, and call irq_work directly if
1785 * there is a pending work.
1786 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001787 spin_lock_irqsave(&wl->wl_lock, flags);
1788 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1789 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1790 run_irq_work = true;
1791 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001792
Eliad Peller4a859df2011-06-06 12:21:52 +03001793 if (run_irq_work) {
1794 wl1271_debug(DEBUG_MAC80211,
1795 "run postponed irq_work directly");
1796 wl1271_irq(0, wl);
1797 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001798 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001799 wl12xx_for_each_wlvif(wl, wlvif) {
1800 wl1271_configure_resume(wl, wlvif);
1801 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001802 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001803
Eliad Peller402e48612011-05-13 11:57:09 +03001804 return 0;
1805}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001806#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001807
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001808static int wl1271_op_start(struct ieee80211_hw *hw)
1809{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001810 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1811
1812 /*
1813 * We have to delay the booting of the hardware because
1814 * we need to know the local MAC address before downloading and
1815 * initializing the firmware. The MAC address cannot be changed
1816 * after boot, and without the proper MAC address, the firmware
1817 * will not function properly.
1818 *
1819 * The MAC address is first known when the corresponding interface
1820 * is added. That is where we will initialize the hardware.
1821 */
1822
1823 return 0;
1824}
1825
1826static void wl1271_op_stop(struct ieee80211_hw *hw)
1827{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001828 struct wl1271 *wl = hw->priv;
1829 int i;
1830
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001831 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001832
Eliad Peller10c8cd02011-10-10 10:13:06 +02001833 mutex_lock(&wl->mutex);
1834 if (wl->state == WL1271_STATE_OFF) {
1835 mutex_unlock(&wl->mutex);
1836 return;
1837 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001838 /*
1839 * this must be before the cancel_work calls below, so that the work
1840 * functions don't perform further work.
1841 */
1842 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001843 mutex_unlock(&wl->mutex);
1844
1845 mutex_lock(&wl_list_mutex);
1846 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001847 mutex_unlock(&wl_list_mutex);
1848
1849 wl1271_disable_interrupts(wl);
1850 wl1271_flush_deferred_work(wl);
1851 cancel_delayed_work_sync(&wl->scan_complete_work);
1852 cancel_work_sync(&wl->netstack_work);
1853 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001854 cancel_delayed_work_sync(&wl->elp_work);
1855
1856 /* let's notify MAC80211 about the remaining pending TX frames */
1857 wl12xx_tx_reset(wl, true);
1858 mutex_lock(&wl->mutex);
1859
1860 wl1271_power_off(wl);
1861
1862 wl->band = IEEE80211_BAND_2GHZ;
1863
1864 wl->rx_counter = 0;
1865 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1866 wl->tx_blocks_available = 0;
1867 wl->tx_allocated_blocks = 0;
1868 wl->tx_results_count = 0;
1869 wl->tx_packets_count = 0;
1870 wl->time_offset = 0;
1871 wl->vif = NULL;
1872 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 Peller536129c2011-10-05 11:55:45 +02001910static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001911{
Eliad Peller536129c2011-10-05 11:55:45 +02001912 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001913 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001914 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001915 return WL1271_ROLE_P2P_GO;
1916 else
1917 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001918
1919 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001920 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001921 return WL1271_ROLE_P2P_CL;
1922 else
1923 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001924
Eliad Peller227e81e2011-08-14 13:17:26 +03001925 case BSS_TYPE_IBSS:
1926 return WL1271_ROLE_IBSS;
1927
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001928 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001929 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001930 }
1931 return WL12XX_INVALID_ROLE_TYPE;
1932}
1933
Eliad Peller83587502011-10-10 10:12:53 +02001934static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001935{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001936 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
1937
Eliad Peller48e93e42011-10-10 10:12:58 +02001938 /* clear everything but the persistent data */
1939 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001940
1941 switch (ieee80211_vif_type_p2p(vif)) {
1942 case NL80211_IFTYPE_P2P_CLIENT:
1943 wlvif->p2p = 1;
1944 /* fall-through */
1945 case NL80211_IFTYPE_STATION:
1946 wlvif->bss_type = BSS_TYPE_STA_BSS;
1947 break;
1948 case NL80211_IFTYPE_ADHOC:
1949 wlvif->bss_type = BSS_TYPE_IBSS;
1950 break;
1951 case NL80211_IFTYPE_P2P_GO:
1952 wlvif->p2p = 1;
1953 /* fall-through */
1954 case NL80211_IFTYPE_AP:
1955 wlvif->bss_type = BSS_TYPE_AP_BSS;
1956 break;
1957 default:
1958 wlvif->bss_type = MAX_BSS_TYPE;
1959 return -EOPNOTSUPP;
1960 }
1961
Eliad Peller0603d892011-10-05 11:55:51 +02001962 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001963 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001964 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001965
Eliad Pellere936bbe2011-10-05 11:55:56 +02001966 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1967 wlvif->bss_type == BSS_TYPE_IBSS) {
1968 /* init sta/ibss data */
1969 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
1970
1971 } else {
1972 /* init ap data */
1973 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1974 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
1975 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001976
Eliad Peller83587502011-10-10 10:12:53 +02001977 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1978 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001979 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001980 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001981 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001982 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1983
Eliad Peller1b92f152011-10-10 10:13:09 +02001984 /*
1985 * mac80211 configures some values globally, while we treat them
1986 * per-interface. thus, on init, we have to copy them from wl
1987 */
1988 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001989 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001990 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02001991
Eliad Peller9eb599e2011-10-10 10:12:59 +02001992 INIT_WORK(&wlvif->rx_streaming_enable_work,
1993 wl1271_rx_streaming_enable_work);
1994 INIT_WORK(&wlvif->rx_streaming_disable_work,
1995 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02001996 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02001997 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001998
Eliad Peller9eb599e2011-10-10 10:12:59 +02001999 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
2000 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002001 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002002}
2003
Eliad Peller1d095472011-10-10 10:12:49 +02002004static bool wl12xx_init_fw(struct wl1271 *wl)
2005{
2006 int retries = WL1271_BOOT_RETRIES;
2007 bool booted = false;
2008 struct wiphy *wiphy = wl->hw->wiphy;
2009 int ret;
2010
2011 while (retries) {
2012 retries--;
2013 ret = wl1271_chip_wakeup(wl);
2014 if (ret < 0)
2015 goto power_off;
2016
2017 ret = wl1271_boot(wl);
2018 if (ret < 0)
2019 goto power_off;
2020
2021 ret = wl1271_hw_init(wl);
2022 if (ret < 0)
2023 goto irq_disable;
2024
2025 booted = true;
2026 break;
2027
2028irq_disable:
2029 mutex_unlock(&wl->mutex);
2030 /* Unlocking the mutex in the middle of handling is
2031 inherently unsafe. In this case we deem it safe to do,
2032 because we need to let any possibly pending IRQ out of
2033 the system (and while we are WL1271_STATE_OFF the IRQ
2034 work function will not do anything.) Also, any other
2035 possible concurrent operations will fail due to the
2036 current state, hence the wl1271 struct should be safe. */
2037 wl1271_disable_interrupts(wl);
2038 wl1271_flush_deferred_work(wl);
2039 cancel_work_sync(&wl->netstack_work);
2040 mutex_lock(&wl->mutex);
2041power_off:
2042 wl1271_power_off(wl);
2043 }
2044
2045 if (!booted) {
2046 wl1271_error("firmware boot failed despite %d retries",
2047 WL1271_BOOT_RETRIES);
2048 goto out;
2049 }
2050
2051 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2052
2053 /* update hw/fw version info in wiphy struct */
2054 wiphy->hw_version = wl->chip.id;
2055 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2056 sizeof(wiphy->fw_version));
2057
2058 /*
2059 * Now we know if 11a is supported (info from the NVS), so disable
2060 * 11a channels if not supported
2061 */
2062 if (!wl->enable_11a)
2063 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2064
2065 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2066 wl->enable_11a ? "" : "not ");
2067
2068 wl->state = WL1271_STATE_ON;
2069out:
2070 return booted;
2071}
2072
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002073static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2074 struct ieee80211_vif *vif)
2075{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002076 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002077 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002078 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002079 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002080 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002081
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002082 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002083 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002084
2085 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002086 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002087 wl1271_debug(DEBUG_MAC80211,
2088 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002089 ret = -EBUSY;
2090 goto out;
2091 }
2092
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002093 /*
2094 * in some very corner case HW recovery scenarios its possible to
2095 * get here before __wl1271_op_remove_interface is complete, so
2096 * opt out if that is the case.
2097 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002098 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2099 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002100 ret = -EBUSY;
2101 goto out;
2102 }
2103
Eliad Peller83587502011-10-10 10:12:53 +02002104 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002105 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002106 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002107
Eliad Peller252efa42011-10-05 11:56:00 +02002108 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002109 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002110 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2111 ret = -EINVAL;
2112 goto out;
2113 }
Eliad Peller1d095472011-10-10 10:12:49 +02002114
Eliad Peller784f6942011-10-05 11:55:39 +02002115 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002116 * TODO: after the nvs issue will be solved, move this block
2117 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002118 */
Eliad Peller1d095472011-10-10 10:12:49 +02002119 if (wl->state == WL1271_STATE_OFF) {
2120 /*
2121 * we still need this in order to configure the fw
2122 * while uploading the nvs
2123 */
2124 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002125
Eliad Peller1d095472011-10-10 10:12:49 +02002126 booted = wl12xx_init_fw(wl);
2127 if (!booted) {
2128 ret = -EINVAL;
2129 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002130 }
Eliad Peller1d095472011-10-10 10:12:49 +02002131 }
Eliad Peller04e80792011-08-14 13:17:09 +03002132
Eliad Peller1d095472011-10-10 10:12:49 +02002133 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2134 wlvif->bss_type == BSS_TYPE_IBSS) {
2135 /*
2136 * The device role is a special role used for
2137 * rx and tx frames prior to association (as
2138 * the STA role can get packets only from
2139 * its associated bssid)
2140 */
Eliad Peller784f6942011-10-05 11:55:39 +02002141 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002142 WL1271_ROLE_DEVICE,
2143 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002144 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002145 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002146 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002147
Eliad Peller1d095472011-10-10 10:12:49 +02002148 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2149 role_type, &wlvif->role_id);
2150 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002151 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002152
2153 ret = wl1271_init_vif_specific(wl, vif);
2154 if (ret < 0)
2155 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002156
2157 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002158 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002159 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002160
2161 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2162 wl->ap_count++;
2163 else
2164 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002165out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002166 mutex_unlock(&wl->mutex);
2167
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002168 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002169 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002170 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002171 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002172
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002173 return ret;
2174}
2175
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002176static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002177 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002178 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002179{
Eliad Peller536129c2011-10-05 11:55:45 +02002180 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002181 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002182
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002183 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002184
Eliad Peller10c8cd02011-10-10 10:13:06 +02002185 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2186 return;
2187
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002188 /* because of hardware recovery, we may get here twice */
2189 if (wl->state != WL1271_STATE_ON)
2190 return;
2191
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002192 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002193
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002194 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002195 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002196 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002197
Eliad Pellerbaf62772011-10-10 10:12:52 +02002198 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2199 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002200 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002201 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002202 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002203 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002204 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002205 }
2206
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002207 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2208 /* disable active roles */
2209 ret = wl1271_ps_elp_wakeup(wl);
2210 if (ret < 0)
2211 goto deinit;
2212
Eliad Peller536129c2011-10-05 11:55:45 +02002213 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002214 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002215 if (ret < 0)
2216 goto deinit;
2217 }
2218
Eliad Peller0603d892011-10-05 11:55:51 +02002219 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002220 if (ret < 0)
2221 goto deinit;
2222
2223 wl1271_ps_elp_sleep(wl);
2224 }
2225deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002226 /* clear all hlids (except system_hlid) */
Eliad Peller154da672011-10-05 11:55:53 +02002227 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002228 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002229 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2230 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002231
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002232 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002233 wl1271_free_ap_keys(wl, wlvif);
Eliad Peller87627212011-10-10 10:12:54 +02002234 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002235 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002236 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002237 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002238
Eliad Pellera4e41302011-10-11 11:49:15 +02002239 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2240 wl->ap_count--;
2241 else
2242 wl->sta_count--;
2243
Eliad Pellerbaf62772011-10-10 10:12:52 +02002244 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002245 del_timer_sync(&wlvif->rx_streaming_timer);
2246 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2247 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002248 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002249
Eliad Pellerbaf62772011-10-10 10:12:52 +02002250 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002251}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002252
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002253static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2254 struct ieee80211_vif *vif)
2255{
2256 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002257 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002258 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002259
2260 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002261
2262 if (wl->state == WL1271_STATE_OFF ||
2263 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2264 goto out;
2265
Juuso Oikarinen67353292010-11-18 15:19:02 +02002266 /*
2267 * wl->vif can be null here if someone shuts down the interface
2268 * just when hardware recovery has been started.
2269 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002270 wl12xx_for_each_wlvif(wl, iter) {
2271 if (iter != wlvif)
2272 continue;
2273
Eliad Peller536129c2011-10-05 11:55:45 +02002274 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002275 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002276 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002277 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002278out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002279 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002280 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002281}
2282
Eliad Peller87fbcb02011-10-05 11:55:41 +02002283static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2284 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002285{
2286 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002287 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002288
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002289 /*
2290 * One of the side effects of the JOIN command is that is clears
2291 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2292 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002293 * Currently the only valid scenario for JOIN during association
2294 * is on roaming, in which case we will also be given new keys.
2295 * Keep the below message for now, unless it starts bothering
2296 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002297 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002298 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002299 wl1271_info("JOIN while associated.");
2300
2301 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002302 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002303
Eliad Peller227e81e2011-08-14 13:17:26 +03002304 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002305 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002306 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002307 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002308 if (ret < 0)
2309 goto out;
2310
Eliad Pellerba8447f2011-10-10 10:13:00 +02002311 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002312 goto out;
2313
2314 /*
2315 * The join command disable the keep-alive mode, shut down its process,
2316 * and also clear the template config, so we need to reset it all after
2317 * the join. The acx_aid starts the keep-alive process, and the order
2318 * of the commands below is relevant.
2319 */
Eliad Peller0603d892011-10-05 11:55:51 +02002320 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002321 if (ret < 0)
2322 goto out;
2323
Eliad Peller0603d892011-10-05 11:55:51 +02002324 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002325 if (ret < 0)
2326 goto out;
2327
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002328 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002329 if (ret < 0)
2330 goto out;
2331
Eliad Peller0603d892011-10-05 11:55:51 +02002332 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2333 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002334 ACX_KEEP_ALIVE_TPL_VALID);
2335 if (ret < 0)
2336 goto out;
2337
2338out:
2339 return ret;
2340}
2341
Eliad Peller0603d892011-10-05 11:55:51 +02002342static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002343{
2344 int ret;
2345
Eliad Peller52630c52011-10-10 10:13:08 +02002346 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002347 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2348
Shahar Levi6d158ff2011-09-08 13:01:33 +03002349 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002350 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002351 }
2352
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002353 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002354 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002355 if (ret < 0)
2356 goto out;
2357
Oz Krakowskib992c682011-06-26 10:36:02 +03002358 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002359 wlvif->tx_security_last_seq_lsb = 0;
2360 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002361
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002362out:
2363 return ret;
2364}
2365
Eliad Peller87fbcb02011-10-05 11:55:41 +02002366static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002367{
Eliad Peller1b92f152011-10-10 10:13:09 +02002368 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002369 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002370}
2371
Eliad Peller251c1772011-08-14 13:17:17 +03002372static bool wl12xx_is_roc(struct wl1271 *wl)
2373{
2374 u8 role_id;
2375
2376 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2377 if (role_id >= WL12XX_MAX_ROLES)
2378 return false;
2379
2380 return true;
2381}
2382
Eliad Peller87fbcb02011-10-05 11:55:41 +02002383static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2384 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002385{
2386 int ret;
2387
2388 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002389 /* no need to croc if we weren't busy (e.g. during boot) */
2390 if (wl12xx_is_roc(wl)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002391 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002392 if (ret < 0)
2393 goto out;
2394
Eliad Peller7edebf52011-10-05 11:55:52 +02002395 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002396 if (ret < 0)
2397 goto out;
2398 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002399 wlvif->rate_set =
2400 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2401 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002402 if (ret < 0)
2403 goto out;
2404 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002405 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002406 ACX_KEEP_ALIVE_TPL_INVALID);
2407 if (ret < 0)
2408 goto out;
2409 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2410 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002411 /* The current firmware only supports sched_scan in idle */
2412 if (wl->sched_scanning) {
2413 wl1271_scan_sched_scan_stop(wl);
2414 ieee80211_sched_scan_stopped(wl->hw);
2415 }
2416
Eliad Peller7edebf52011-10-05 11:55:52 +02002417 ret = wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002418 if (ret < 0)
2419 goto out;
2420
Eliad Peller1b92f152011-10-10 10:13:09 +02002421 ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002422 if (ret < 0)
2423 goto out;
2424 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2425 }
2426
2427out:
2428 return ret;
2429}
2430
Eliad Peller9f259c42011-10-10 10:13:12 +02002431static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2432 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002433{
Eliad Peller9f259c42011-10-10 10:13:12 +02002434 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2435 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002436
2437 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2438
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002439 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002440 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002441 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002442 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002443 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002444 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002445 wlvif->band = conf->channel->band;
2446 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002447
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002448 if (!is_ap) {
2449 /*
2450 * FIXME: the mac80211 should really provide a fixed
2451 * rate to use here. for now, just use the smallest
2452 * possible rate for the band as a fixed rate for
2453 * association frames and other control messages.
2454 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002455 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002456 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002457
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002458 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002459 wl1271_tx_min_rate_get(wl,
2460 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002461 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002462 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002463 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002464 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002465
Eliad Pellerba8447f2011-10-10 10:13:00 +02002466 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2467 &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002468 if (wl12xx_is_roc(wl)) {
2469 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002470 ret = wl12xx_croc(wl,
2471 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002472 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002473 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002474 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002475 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002476 if (ret < 0)
2477 wl1271_warning("cmd join on channel "
2478 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002479 } else {
2480 /*
2481 * change the ROC channel. do it only if we are
2482 * not idle. otherwise, CROC will be called
2483 * anyway.
2484 */
2485 if (wl12xx_is_roc(wl) &&
2486 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002487 ret = wl12xx_croc(wl,
2488 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002489 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002490 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002491
Eliad Peller1b92f152011-10-10 10:13:09 +02002492 ret = wl12xx_roc(wl, wlvif,
Eliad Peller7edebf52011-10-05 11:55:52 +02002493 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002494 if (ret < 0)
2495 wl1271_warning("roc failed %d",
2496 ret);
2497 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002498 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002499 }
2500 }
2501
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002502 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002503 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002504 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002505 if (ret < 0)
2506 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002507 }
2508
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002509 /*
2510 * if mac80211 changes the PSM mode, make sure the mode is not
2511 * incorrectly changed after the pspoll failure active window.
2512 */
2513 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002514 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002515
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002516 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002517 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2518 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002519
2520 /*
2521 * We enter PSM only if we're already associated.
2522 * If we're not, we'll enter it when joining an SSID,
2523 * through the bss_info_changed() hook.
2524 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002525 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002526 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002527 ret = wl1271_ps_set_mode(wl, wlvif,
2528 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002529 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002530 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002531 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002532 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002533 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002534
Eliad Pellerc29bb002011-10-10 10:13:03 +02002535 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002536
Eliad Pellerc29bb002011-10-10 10:13:03 +02002537 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002538 ret = wl1271_ps_set_mode(wl, wlvif,
2539 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002540 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002541 }
2542
Eliad Peller6bd65022011-10-10 10:13:11 +02002543 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002544 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002545 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002546 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002547
Eliad Peller6bd65022011-10-10 10:13:11 +02002548 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002549 }
2550
Eliad Peller9f259c42011-10-10 10:13:12 +02002551 return 0;
2552}
2553
2554static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2555{
2556 struct wl1271 *wl = hw->priv;
2557 struct wl12xx_vif *wlvif;
2558 struct ieee80211_conf *conf = &hw->conf;
2559 int channel, ret = 0;
2560
2561 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2562
2563 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2564 " changed 0x%x",
2565 channel,
2566 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2567 conf->power_level,
2568 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2569 changed);
2570
2571 /*
2572 * mac80211 will go to idle nearly immediately after transmitting some
2573 * frames, such as the deauth. To make sure those frames reach the air,
2574 * wait here until the TX queue is fully flushed.
2575 */
2576 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2577 (conf->flags & IEEE80211_CONF_IDLE))
2578 wl1271_tx_flush(wl);
2579
2580 mutex_lock(&wl->mutex);
2581
2582 /* we support configuring the channel and band even while off */
2583 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2584 wl->band = conf->channel->band;
2585 wl->channel = channel;
2586 }
2587
2588 if (changed & IEEE80211_CONF_CHANGE_POWER)
2589 wl->power_level = conf->power_level;
2590
2591 if (unlikely(wl->state == WL1271_STATE_OFF))
2592 goto out;
2593
2594 ret = wl1271_ps_elp_wakeup(wl);
2595 if (ret < 0)
2596 goto out;
2597
2598 /* configure each interface */
2599 wl12xx_for_each_wlvif(wl, wlvif) {
2600 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2601 if (ret < 0)
2602 goto out_sleep;
2603 }
2604
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002605out_sleep:
2606 wl1271_ps_elp_sleep(wl);
2607
2608out:
2609 mutex_unlock(&wl->mutex);
2610
2611 return ret;
2612}
2613
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002614struct wl1271_filter_params {
2615 bool enabled;
2616 int mc_list_length;
2617 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2618};
2619
Jiri Pirko22bedad2010-04-01 21:22:57 +00002620static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2621 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002622{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002623 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002624 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002625 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002626
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002627 if (unlikely(wl->state == WL1271_STATE_OFF))
2628 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002629
Juuso Oikarinen74441132009-10-13 12:47:53 +03002630 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002631 if (!fp) {
2632 wl1271_error("Out of memory setting filters.");
2633 return 0;
2634 }
2635
2636 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002637 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002638 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2639 fp->enabled = false;
2640 } else {
2641 fp->enabled = true;
2642 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002643 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002644 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002645 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002646 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002647 }
2648
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002649 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002650}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002651
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002652#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2653 FIF_ALLMULTI | \
2654 FIF_FCSFAIL | \
2655 FIF_BCN_PRBRESP_PROMISC | \
2656 FIF_CONTROL | \
2657 FIF_OTHER_BSS)
2658
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002659static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2660 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002661 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002662{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002663 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002664 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002665 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002666
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002667 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002668
Arik Nemtsov7d057862010-10-16 19:25:35 +02002669 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2670 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002671
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002672 mutex_lock(&wl->mutex);
2673
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002674 *total &= WL1271_SUPPORTED_FILTERS;
2675 changed &= WL1271_SUPPORTED_FILTERS;
2676
2677 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002678 goto out;
2679
Ido Yariva6208652011-03-01 15:14:41 +02002680 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002681 if (ret < 0)
2682 goto out;
2683
Eliad Peller6e8cd332011-10-10 10:13:13 +02002684 wl12xx_for_each_wlvif(wl, wlvif) {
2685 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2686 if (*total & FIF_ALLMULTI)
2687 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2688 false,
2689 NULL, 0);
2690 else if (fp)
2691 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2692 fp->enabled,
2693 fp->mc_list,
2694 fp->mc_list_length);
2695 if (ret < 0)
2696 goto out_sleep;
2697 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002698 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002699
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002700 /*
2701 * the fw doesn't provide an api to configure the filters. instead,
2702 * the filters configuration is based on the active roles / ROC
2703 * state.
2704 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002705
2706out_sleep:
2707 wl1271_ps_elp_sleep(wl);
2708
2709out:
2710 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002711 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002712}
2713
Eliad Peller170d0e62011-10-05 11:56:06 +02002714static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2715 u8 id, u8 key_type, u8 key_size,
2716 const u8 *key, u8 hlid, u32 tx_seq_32,
2717 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002718{
2719 struct wl1271_ap_key *ap_key;
2720 int i;
2721
2722 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2723
2724 if (key_size > MAX_KEY_SIZE)
2725 return -EINVAL;
2726
2727 /*
2728 * Find next free entry in ap_keys. Also check we are not replacing
2729 * an existing key.
2730 */
2731 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002732 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002733 break;
2734
Eliad Peller170d0e62011-10-05 11:56:06 +02002735 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002736 wl1271_warning("trying to record key replacement");
2737 return -EINVAL;
2738 }
2739 }
2740
2741 if (i == MAX_NUM_KEYS)
2742 return -EBUSY;
2743
2744 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2745 if (!ap_key)
2746 return -ENOMEM;
2747
2748 ap_key->id = id;
2749 ap_key->key_type = key_type;
2750 ap_key->key_size = key_size;
2751 memcpy(ap_key->key, key, key_size);
2752 ap_key->hlid = hlid;
2753 ap_key->tx_seq_32 = tx_seq_32;
2754 ap_key->tx_seq_16 = tx_seq_16;
2755
Eliad Peller170d0e62011-10-05 11:56:06 +02002756 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002757 return 0;
2758}
2759
Eliad Peller170d0e62011-10-05 11:56:06 +02002760static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002761{
2762 int i;
2763
2764 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002765 kfree(wlvif->ap.recorded_keys[i]);
2766 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002767 }
2768}
2769
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002770static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002771{
2772 int i, ret = 0;
2773 struct wl1271_ap_key *key;
2774 bool wep_key_added = false;
2775
2776 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002777 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002778 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002779 break;
2780
Eliad Peller170d0e62011-10-05 11:56:06 +02002781 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002782 hlid = key->hlid;
2783 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002784 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002785
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002786 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002787 key->id, key->key_type,
2788 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002789 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002790 key->tx_seq_16);
2791 if (ret < 0)
2792 goto out;
2793
2794 if (key->key_type == KEY_WEP)
2795 wep_key_added = true;
2796 }
2797
2798 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002799 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002800 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002801 if (ret < 0)
2802 goto out;
2803 }
2804
2805out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002806 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002807 return ret;
2808}
2809
Eliad Peller536129c2011-10-05 11:55:45 +02002810static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2811 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002812 u8 key_size, const u8 *key, u32 tx_seq_32,
2813 u16 tx_seq_16, struct ieee80211_sta *sta)
2814{
2815 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002816 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002817
2818 if (is_ap) {
2819 struct wl1271_station *wl_sta;
2820 u8 hlid;
2821
2822 if (sta) {
2823 wl_sta = (struct wl1271_station *)sta->drv_priv;
2824 hlid = wl_sta->hlid;
2825 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002826 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002827 }
2828
Eliad Peller53d40d02011-10-10 10:13:02 +02002829 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002830 /*
2831 * We do not support removing keys after AP shutdown.
2832 * Pretend we do to make mac80211 happy.
2833 */
2834 if (action != KEY_ADD_OR_REPLACE)
2835 return 0;
2836
Eliad Peller170d0e62011-10-05 11:56:06 +02002837 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002838 key_type, key_size,
2839 key, hlid, tx_seq_32,
2840 tx_seq_16);
2841 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002842 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002843 id, key_type, key_size,
2844 key, hlid, tx_seq_32,
2845 tx_seq_16);
2846 }
2847
2848 if (ret < 0)
2849 return ret;
2850 } else {
2851 const u8 *addr;
2852 static const u8 bcast_addr[ETH_ALEN] = {
2853 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2854 };
2855
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002856 /*
2857 * A STA set to GEM cipher requires 2 tx spare blocks.
2858 * Return to default value when GEM cipher key is removed
2859 */
2860 if (key_type == KEY_GEM) {
2861 if (action == KEY_ADD_OR_REPLACE)
2862 wl->tx_spare_blocks = 2;
2863 else if (action == KEY_REMOVE)
2864 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2865 }
2866
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002867 addr = sta ? sta->addr : bcast_addr;
2868
2869 if (is_zero_ether_addr(addr)) {
2870 /* We dont support TX only encryption */
2871 return -EOPNOTSUPP;
2872 }
2873
2874 /* The wl1271 does not allow to remove unicast keys - they
2875 will be cleared automatically on next CMD_JOIN. Ignore the
2876 request silently, as we dont want the mac80211 to emit
2877 an error message. */
2878 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2879 return 0;
2880
Eliad Peller010d3d32011-08-14 13:17:31 +03002881 /* don't remove key if hlid was already deleted */
2882 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002883 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002884 return 0;
2885
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002886 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002887 id, key_type, key_size,
2888 key, addr, tx_seq_32,
2889 tx_seq_16);
2890 if (ret < 0)
2891 return ret;
2892
2893 /* the default WEP key needs to be configured at least once */
2894 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002895 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002896 wlvif->default_key,
2897 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002898 if (ret < 0)
2899 return ret;
2900 }
2901 }
2902
2903 return 0;
2904}
2905
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002906static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2907 struct ieee80211_vif *vif,
2908 struct ieee80211_sta *sta,
2909 struct ieee80211_key_conf *key_conf)
2910{
2911 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002912 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002913 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002914 u32 tx_seq_32 = 0;
2915 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002916 u8 key_type;
2917
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002918 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2919
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002920 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002921 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002922 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002923 key_conf->keylen, key_conf->flags);
2924 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2925
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002926 mutex_lock(&wl->mutex);
2927
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002928 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2929 ret = -EAGAIN;
2930 goto out_unlock;
2931 }
2932
Ido Yariva6208652011-03-01 15:14:41 +02002933 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002934 if (ret < 0)
2935 goto out_unlock;
2936
Johannes Berg97359d12010-08-10 09:46:38 +02002937 switch (key_conf->cipher) {
2938 case WLAN_CIPHER_SUITE_WEP40:
2939 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002940 key_type = KEY_WEP;
2941
2942 key_conf->hw_key_idx = key_conf->keyidx;
2943 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002944 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002945 key_type = KEY_TKIP;
2946
2947 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002948 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2949 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002950 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002951 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002952 key_type = KEY_AES;
2953
2954 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Eliad Peller48e93e42011-10-10 10:12:58 +02002955 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2956 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002957 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002958 case WL1271_CIPHER_SUITE_GEM:
2959 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002960 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2961 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002962 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002963 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002964 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002965
2966 ret = -EOPNOTSUPP;
2967 goto out_sleep;
2968 }
2969
2970 switch (cmd) {
2971 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002972 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002973 key_conf->keyidx, key_type,
2974 key_conf->keylen, key_conf->key,
2975 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002976 if (ret < 0) {
2977 wl1271_error("Could not add or replace key");
2978 goto out_sleep;
2979 }
2980 break;
2981
2982 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002983 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002984 key_conf->keyidx, key_type,
2985 key_conf->keylen, key_conf->key,
2986 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002987 if (ret < 0) {
2988 wl1271_error("Could not remove key");
2989 goto out_sleep;
2990 }
2991 break;
2992
2993 default:
2994 wl1271_error("Unsupported key cmd 0x%x", cmd);
2995 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002996 break;
2997 }
2998
2999out_sleep:
3000 wl1271_ps_elp_sleep(wl);
3001
3002out_unlock:
3003 mutex_unlock(&wl->mutex);
3004
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003005 return ret;
3006}
3007
3008static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003009 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003010 struct cfg80211_scan_request *req)
3011{
3012 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003013 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3014
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003015 int ret;
3016 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003017 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003018
3019 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3020
3021 if (req->n_ssids) {
3022 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003023 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003024 }
3025
3026 mutex_lock(&wl->mutex);
3027
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003028 if (wl->state == WL1271_STATE_OFF) {
3029 /*
3030 * We cannot return -EBUSY here because cfg80211 will expect
3031 * a call to ieee80211_scan_completed if we do - in this case
3032 * there won't be any call.
3033 */
3034 ret = -EAGAIN;
3035 goto out;
3036 }
3037
Ido Yariva6208652011-03-01 15:14:41 +02003038 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003039 if (ret < 0)
3040 goto out;
3041
Eliad Peller251c1772011-08-14 13:17:17 +03003042 /* cancel ROC before scanning */
3043 if (wl12xx_is_roc(wl)) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02003044 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03003045 /* don't allow scanning right now */
3046 ret = -EBUSY;
3047 goto out_sleep;
3048 }
Eliad Peller7edebf52011-10-05 11:55:52 +02003049 wl12xx_croc(wl, wlvif->dev_role_id);
3050 wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003051 }
3052
Eliad Peller784f6942011-10-05 11:55:39 +02003053 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003054out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003055 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003056out:
3057 mutex_unlock(&wl->mutex);
3058
3059 return ret;
3060}
3061
Eliad Peller73ecce32011-06-27 13:06:45 +03003062static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3063 struct ieee80211_vif *vif)
3064{
3065 struct wl1271 *wl = hw->priv;
3066 int ret;
3067
3068 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3069
3070 mutex_lock(&wl->mutex);
3071
3072 if (wl->state == WL1271_STATE_OFF)
3073 goto out;
3074
3075 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3076 goto out;
3077
3078 ret = wl1271_ps_elp_wakeup(wl);
3079 if (ret < 0)
3080 goto out;
3081
3082 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3083 ret = wl1271_scan_stop(wl);
3084 if (ret < 0)
3085 goto out_sleep;
3086 }
3087 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3088 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003089 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003090 wl->scan.req = NULL;
3091 ieee80211_scan_completed(wl->hw, true);
3092
3093out_sleep:
3094 wl1271_ps_elp_sleep(wl);
3095out:
3096 mutex_unlock(&wl->mutex);
3097
3098 cancel_delayed_work_sync(&wl->scan_complete_work);
3099}
3100
Luciano Coelho33c2c062011-05-10 14:46:02 +03003101static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3102 struct ieee80211_vif *vif,
3103 struct cfg80211_sched_scan_request *req,
3104 struct ieee80211_sched_scan_ies *ies)
3105{
3106 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003107 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003108 int ret;
3109
3110 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3111
3112 mutex_lock(&wl->mutex);
3113
3114 ret = wl1271_ps_elp_wakeup(wl);
3115 if (ret < 0)
3116 goto out;
3117
Eliad Peller536129c2011-10-05 11:55:45 +02003118 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003119 if (ret < 0)
3120 goto out_sleep;
3121
Eliad Peller536129c2011-10-05 11:55:45 +02003122 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003123 if (ret < 0)
3124 goto out_sleep;
3125
3126 wl->sched_scanning = true;
3127
3128out_sleep:
3129 wl1271_ps_elp_sleep(wl);
3130out:
3131 mutex_unlock(&wl->mutex);
3132 return ret;
3133}
3134
3135static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3136 struct ieee80211_vif *vif)
3137{
3138 struct wl1271 *wl = hw->priv;
3139 int ret;
3140
3141 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3142
3143 mutex_lock(&wl->mutex);
3144
3145 ret = wl1271_ps_elp_wakeup(wl);
3146 if (ret < 0)
3147 goto out;
3148
3149 wl1271_scan_sched_scan_stop(wl);
3150
3151 wl1271_ps_elp_sleep(wl);
3152out:
3153 mutex_unlock(&wl->mutex);
3154}
3155
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003156static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3157{
3158 struct wl1271 *wl = hw->priv;
3159 int ret = 0;
3160
3161 mutex_lock(&wl->mutex);
3162
3163 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3164 ret = -EAGAIN;
3165 goto out;
3166 }
3167
Ido Yariva6208652011-03-01 15:14:41 +02003168 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003169 if (ret < 0)
3170 goto out;
3171
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003172 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003173 if (ret < 0)
3174 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3175
3176 wl1271_ps_elp_sleep(wl);
3177
3178out:
3179 mutex_unlock(&wl->mutex);
3180
3181 return ret;
3182}
3183
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003184static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3185{
3186 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003187 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003188 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003189
3190 mutex_lock(&wl->mutex);
3191
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003192 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3193 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003194 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003195 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003196
Ido Yariva6208652011-03-01 15:14:41 +02003197 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003198 if (ret < 0)
3199 goto out;
3200
Eliad Peller6e8cd332011-10-10 10:13:13 +02003201 wl12xx_for_each_wlvif(wl, wlvif) {
3202 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3203 if (ret < 0)
3204 wl1271_warning("set rts threshold failed: %d", ret);
3205 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003206 wl1271_ps_elp_sleep(wl);
3207
3208out:
3209 mutex_unlock(&wl->mutex);
3210
3211 return ret;
3212}
3213
Eliad Peller1fe9f162011-10-05 11:55:48 +02003214static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003215 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003216{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003217 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003218 u8 ssid_len;
3219 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3220 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003221
Eliad Peller889cb362011-05-01 09:56:45 +03003222 if (!ptr) {
3223 wl1271_error("No SSID in IEs!");
3224 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003225 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003226
Eliad Peller889cb362011-05-01 09:56:45 +03003227 ssid_len = ptr[1];
3228 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3229 wl1271_error("SSID is too long!");
3230 return -EINVAL;
3231 }
3232
Eliad Peller1fe9f162011-10-05 11:55:48 +02003233 wlvif->ssid_len = ssid_len;
3234 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003235 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003236}
3237
Eliad Pellerd48055d2011-09-15 12:07:04 +03003238static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3239{
3240 int len;
3241 const u8 *next, *end = skb->data + skb->len;
3242 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3243 skb->len - ieoffset);
3244 if (!ie)
3245 return;
3246 len = ie[1] + 2;
3247 next = ie + len;
3248 memmove(ie, next, end - next);
3249 skb_trim(skb, skb->len - len);
3250}
3251
Eliad Peller26b4bf22011-09-15 12:07:05 +03003252static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3253 unsigned int oui, u8 oui_type,
3254 int ieoffset)
3255{
3256 int len;
3257 const u8 *next, *end = skb->data + skb->len;
3258 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3259 skb->data + ieoffset,
3260 skb->len - ieoffset);
3261 if (!ie)
3262 return;
3263 len = ie[1] + 2;
3264 next = ie + len;
3265 memmove(ie, next, end - next);
3266 skb_trim(skb, skb->len - len);
3267}
3268
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003269static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
Eliad Peller1fe9f162011-10-05 11:55:48 +02003270 struct ieee80211_vif *vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003271 u8 *probe_rsp_data,
3272 size_t probe_rsp_len,
3273 u32 rates)
3274{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003275 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3276 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003277 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3278 int ssid_ie_offset, ie_offset, templ_len;
3279 const u8 *ptr;
3280
3281 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003282 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003283 return wl1271_cmd_template_set(wl,
3284 CMD_TEMPL_AP_PROBE_RESPONSE,
3285 probe_rsp_data,
3286 probe_rsp_len, 0,
3287 rates);
3288
3289 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3290 wl1271_error("probe_rsp template too big");
3291 return -EINVAL;
3292 }
3293
3294 /* start searching from IE offset */
3295 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3296
3297 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3298 probe_rsp_len - ie_offset);
3299 if (!ptr) {
3300 wl1271_error("No SSID in beacon!");
3301 return -EINVAL;
3302 }
3303
3304 ssid_ie_offset = ptr - probe_rsp_data;
3305 ptr += (ptr[1] + 2);
3306
3307 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3308
3309 /* insert SSID from bss_conf */
3310 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3311 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3312 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3313 bss_conf->ssid, bss_conf->ssid_len);
3314 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3315
3316 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3317 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3318 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3319
3320 return wl1271_cmd_template_set(wl,
3321 CMD_TEMPL_AP_PROBE_RESPONSE,
3322 probe_rsp_templ,
3323 templ_len, 0,
3324 rates);
3325}
3326
Arik Nemtsove78a2872010-10-16 19:07:21 +02003327static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003328 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003329 struct ieee80211_bss_conf *bss_conf,
3330 u32 changed)
3331{
Eliad Peller0603d892011-10-05 11:55:51 +02003332 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003333 int ret = 0;
3334
3335 if (changed & BSS_CHANGED_ERP_SLOT) {
3336 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003337 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003338 else
Eliad Peller0603d892011-10-05 11:55:51 +02003339 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003340 if (ret < 0) {
3341 wl1271_warning("Set slot time failed %d", ret);
3342 goto out;
3343 }
3344 }
3345
3346 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3347 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003348 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003349 else
Eliad Peller0603d892011-10-05 11:55:51 +02003350 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003351 }
3352
3353 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3354 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003355 ret = wl1271_acx_cts_protect(wl, wlvif,
3356 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003357 else
Eliad Peller0603d892011-10-05 11:55:51 +02003358 ret = wl1271_acx_cts_protect(wl, wlvif,
3359 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003360 if (ret < 0) {
3361 wl1271_warning("Set ctsprotect failed %d", ret);
3362 goto out;
3363 }
3364 }
3365
3366out:
3367 return ret;
3368}
3369
3370static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3371 struct ieee80211_vif *vif,
3372 struct ieee80211_bss_conf *bss_conf,
3373 u32 changed)
3374{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003375 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003376 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003377 int ret = 0;
3378
3379 if ((changed & BSS_CHANGED_BEACON_INT)) {
3380 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3381 bss_conf->beacon_int);
3382
Eliad Peller6a899792011-10-05 11:55:58 +02003383 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003384 }
3385
3386 if ((changed & BSS_CHANGED_BEACON)) {
3387 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003388 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003389 int ieoffset = offsetof(struct ieee80211_mgmt,
3390 u.beacon.variable);
3391 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3392 u16 tmpl_id;
3393
3394 if (!beacon)
3395 goto out;
3396
3397 wl1271_debug(DEBUG_MASTER, "beacon updated");
3398
Eliad Peller1fe9f162011-10-05 11:55:48 +02003399 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003400 if (ret < 0) {
3401 dev_kfree_skb(beacon);
3402 goto out;
3403 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003404 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003405 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3406 CMD_TEMPL_BEACON;
3407 ret = wl1271_cmd_template_set(wl, tmpl_id,
3408 beacon->data,
3409 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003410 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003411 if (ret < 0) {
3412 dev_kfree_skb(beacon);
3413 goto out;
3414 }
3415
Eliad Pellerd48055d2011-09-15 12:07:04 +03003416 /* remove TIM ie from probe response */
3417 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3418
Eliad Peller26b4bf22011-09-15 12:07:05 +03003419 /*
3420 * remove p2p ie from probe response.
3421 * the fw reponds to probe requests that don't include
3422 * the p2p ie. probe requests with p2p ie will be passed,
3423 * and will be responded by the supplicant (the spec
3424 * forbids including the p2p ie when responding to probe
3425 * requests that didn't include it).
3426 */
3427 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3428 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3429
Arik Nemtsove78a2872010-10-16 19:07:21 +02003430 hdr = (struct ieee80211_hdr *) beacon->data;
3431 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3432 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003433 if (is_ap)
Eliad Peller1fe9f162011-10-05 11:55:48 +02003434 ret = wl1271_ap_set_probe_resp_tmpl(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003435 beacon->data,
3436 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003437 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003438 else
3439 ret = wl1271_cmd_template_set(wl,
3440 CMD_TEMPL_PROBE_RESPONSE,
3441 beacon->data,
3442 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003443 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003444 dev_kfree_skb(beacon);
3445 if (ret < 0)
3446 goto out;
3447 }
3448
3449out:
3450 return ret;
3451}
3452
3453/* AP mode changes */
3454static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003455 struct ieee80211_vif *vif,
3456 struct ieee80211_bss_conf *bss_conf,
3457 u32 changed)
3458{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003459 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003460 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003461
Arik Nemtsove78a2872010-10-16 19:07:21 +02003462 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3463 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003464
Eliad Peller87fbcb02011-10-05 11:55:41 +02003465 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003466 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003467 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003468 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003469
Eliad Peller87fbcb02011-10-05 11:55:41 +02003470 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003471 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003472 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003473 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003474 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003475
Eliad Peller784f6942011-10-05 11:55:39 +02003476 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003477 if (ret < 0)
3478 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003479 }
3480
Arik Nemtsove78a2872010-10-16 19:07:21 +02003481 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3482 if (ret < 0)
3483 goto out;
3484
3485 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3486 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003487 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003488 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003489 if (ret < 0)
3490 goto out;
3491
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003492 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003493 if (ret < 0)
3494 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003495
Eliad Peller53d40d02011-10-10 10:13:02 +02003496 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003497 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003498 }
3499 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003500 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003501 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003502 if (ret < 0)
3503 goto out;
3504
Eliad Peller53d40d02011-10-10 10:13:02 +02003505 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003506 wl1271_debug(DEBUG_AP, "stopped AP");
3507 }
3508 }
3509 }
3510
Eliad Peller0603d892011-10-05 11:55:51 +02003511 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003512 if (ret < 0)
3513 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003514
3515 /* Handle HT information change */
3516 if ((changed & BSS_CHANGED_HT) &&
3517 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003518 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003519 bss_conf->ht_operation_mode);
3520 if (ret < 0) {
3521 wl1271_warning("Set ht information failed %d", ret);
3522 goto out;
3523 }
3524 }
3525
Arik Nemtsove78a2872010-10-16 19:07:21 +02003526out:
3527 return;
3528}
3529
3530/* STA/IBSS mode changes */
3531static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3532 struct ieee80211_vif *vif,
3533 struct ieee80211_bss_conf *bss_conf,
3534 u32 changed)
3535{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003536 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003537 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003538 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003539 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003540 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003541 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003542 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003543 bool sta_exists = false;
3544 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003545
3546 if (is_ibss) {
3547 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3548 changed);
3549 if (ret < 0)
3550 goto out;
3551 }
3552
Eliad Peller227e81e2011-08-14 13:17:26 +03003553 if (changed & BSS_CHANGED_IBSS) {
3554 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003555 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003556 ibss_joined = true;
3557 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003558 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3559 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003560 wl1271_unjoin(wl, wlvif);
Eliad Peller7edebf52011-10-05 11:55:52 +02003561 wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller1b92f152011-10-10 10:13:09 +02003562 wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
Eliad Peller227e81e2011-08-14 13:17:26 +03003563 }
3564 }
3565 }
3566
3567 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003568 do_join = true;
3569
3570 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003571 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003572 do_join = true;
3573
Eliad Peller227e81e2011-08-14 13:17:26 +03003574 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003575 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3576 bss_conf->enable_beacon ? "enabled" : "disabled");
3577
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003578 do_join = true;
3579 }
3580
Arik Nemtsove78a2872010-10-16 19:07:21 +02003581 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003582 bool enable = false;
3583 if (bss_conf->cqm_rssi_thold)
3584 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003585 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003586 bss_conf->cqm_rssi_thold,
3587 bss_conf->cqm_rssi_hyst);
3588 if (ret < 0)
3589 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003590 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003591 }
3592
Eliad Pellercdf09492011-10-05 11:55:44 +02003593 if (changed & BSS_CHANGED_BSSID)
3594 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003595 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003596 if (ret < 0)
3597 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003598
Eliad Peller784f6942011-10-05 11:55:39 +02003599 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003600 if (ret < 0)
3601 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003602
Eliad Pellerfa287b82010-12-26 09:27:50 +01003603 /* Need to update the BSSID (for filtering etc) */
3604 do_join = true;
3605 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003606
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003607 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3608 rcu_read_lock();
3609 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3610 if (!sta)
3611 goto sta_not_found;
3612
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003613 /* save the supp_rates of the ap */
3614 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3615 if (sta->ht_cap.ht_supported)
3616 sta_rate_set |=
3617 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003618 sta_ht_cap = sta->ht_cap;
3619 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003620
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003621sta_not_found:
3622 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003623 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003624
Arik Nemtsove78a2872010-10-16 19:07:21 +02003625 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003626 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003627 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003628 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003629 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003630 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003631
Eliad Peller74ec8392011-10-05 11:56:02 +02003632 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003633
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003634 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003635 * use basic rates from AP, and determine lowest rate
3636 * to use with control frames.
3637 */
3638 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003639 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003640 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003641 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003642 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003643 wl1271_tx_min_rate_get(wl,
3644 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003645 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003646 wlvif->rate_set =
3647 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003648 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003649 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003650 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003651 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003652 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003653
3654 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003655 * with wl1271, we don't need to update the
3656 * beacon_int and dtim_period, because the firmware
3657 * updates it by itself when the first beacon is
3658 * received after a join.
3659 */
Eliad Peller6840e372011-10-05 11:55:50 +02003660 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003661 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003662 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003663
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003664 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003665 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003666 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003667 dev_kfree_skb(wlvif->probereq);
3668 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003669 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003670 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003671 ieoffset = offsetof(struct ieee80211_mgmt,
3672 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003673 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003674
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003675 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003676 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003677 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003678 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003679 } else {
3680 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003681 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003682 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3683 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003684 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003685 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3686 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003687 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003688
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003689 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003690 dev_kfree_skb(wlvif->probereq);
3691 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003692
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003693 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003694 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003695
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003696 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003697 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003698 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003699 wl1271_tx_min_rate_get(wl,
3700 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003701 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003702 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003703 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003704
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003705 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003706 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003707
3708 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003709 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003710 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003711 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003712
3713 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003714 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003715 u32 conf_flags = wl->hw->conf.flags;
3716 /*
3717 * we might have to disable roc, if there was
3718 * no IF_OPER_UP notification.
3719 */
3720 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003721 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003722 if (ret < 0)
3723 goto out;
3724 }
3725 /*
3726 * (we also need to disable roc in case of
3727 * roaming on the same channel. until we will
3728 * have a better flow...)
3729 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003730 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3731 ret = wl12xx_croc(wl,
3732 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003733 if (ret < 0)
3734 goto out;
3735 }
3736
Eliad Peller0603d892011-10-05 11:55:51 +02003737 wl1271_unjoin(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003738 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02003739 wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller1b92f152011-10-10 10:13:09 +02003740 wl12xx_roc(wl, wlvif,
3741 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003742 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003743 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003744 }
3745 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003746
Eliad Pellerd192d262011-05-24 14:33:08 +03003747 if (changed & BSS_CHANGED_IBSS) {
3748 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3749 bss_conf->ibss_joined);
3750
3751 if (bss_conf->ibss_joined) {
3752 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003753 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003754 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003755 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003756 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003757 wl1271_tx_min_rate_get(wl,
3758 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003759
Shahar Levi06b660e2011-09-05 13:54:36 +03003760 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003761 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3762 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003763 if (ret < 0)
3764 goto out;
3765 }
3766 }
3767
Eliad Peller0603d892011-10-05 11:55:51 +02003768 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003769 if (ret < 0)
3770 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003771
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003772 if (changed & BSS_CHANGED_ARP_FILTER) {
3773 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003774 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003775
Eliad Pellerc5312772010-12-09 11:31:27 +02003776 if (bss_conf->arp_addr_cnt == 1 &&
3777 bss_conf->arp_filter_enabled) {
3778 /*
3779 * The template should have been configured only upon
3780 * association. however, it seems that the correct ip
3781 * isn't being set (when sending), so we have to
3782 * reconfigure the template upon every ip change.
3783 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003784 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003785 if (ret < 0) {
3786 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003787 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003788 }
3789
Eliad Peller0603d892011-10-05 11:55:51 +02003790 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003791 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003792 addr);
3793 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003794 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003795
3796 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003797 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003798 }
3799
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003800 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003801 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003802 if (ret < 0) {
3803 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003804 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003805 }
Eliad Peller251c1772011-08-14 13:17:17 +03003806
3807 /* ROC until connected (after EAPOL exchange) */
3808 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003809 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003810 if (ret < 0)
3811 goto out;
3812
Eliad Pellerba8447f2011-10-10 10:13:00 +02003813 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003814 ieee80211_get_operstate(vif));
3815 }
3816 /*
3817 * stop device role if started (we might already be in
3818 * STA role). TODO: make it better.
3819 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003820 if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3821 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003822 if (ret < 0)
3823 goto out;
3824
Eliad Peller7edebf52011-10-05 11:55:52 +02003825 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003826 if (ret < 0)
3827 goto out;
3828 }
Eliad Peller05dba352011-08-23 16:37:01 +03003829
3830 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003831 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3832 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003833 enum wl1271_cmd_ps_mode mode;
3834
3835 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003836 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003837 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003838 true);
3839 if (ret < 0)
3840 goto out;
3841 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003842 }
3843
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003844 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003845 if (sta_exists) {
3846 if ((changed & BSS_CHANGED_HT) &&
3847 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003848 ret = wl1271_acx_set_ht_capabilities(wl,
3849 &sta_ht_cap,
3850 true,
Eliad Peller154da672011-10-05 11:55:53 +02003851 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003852 if (ret < 0) {
3853 wl1271_warning("Set ht cap true failed %d",
3854 ret);
3855 goto out;
3856 }
3857 }
3858 /* handle new association without HT and disassociation */
3859 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003860 ret = wl1271_acx_set_ht_capabilities(wl,
3861 &sta_ht_cap,
3862 false,
Eliad Peller154da672011-10-05 11:55:53 +02003863 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003864 if (ret < 0) {
3865 wl1271_warning("Set ht cap false failed %d",
3866 ret);
3867 goto out;
3868 }
3869 }
3870 }
3871
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003872 /* Handle HT information change. Done after join. */
3873 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003874 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003875 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003876 bss_conf->ht_operation_mode);
3877 if (ret < 0) {
3878 wl1271_warning("Set ht information failed %d", ret);
3879 goto out;
3880 }
3881 }
3882
Arik Nemtsove78a2872010-10-16 19:07:21 +02003883out:
3884 return;
3885}
3886
3887static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3888 struct ieee80211_vif *vif,
3889 struct ieee80211_bss_conf *bss_conf,
3890 u32 changed)
3891{
3892 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003893 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3894 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003895 int ret;
3896
3897 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3898 (int)changed);
3899
3900 mutex_lock(&wl->mutex);
3901
3902 if (unlikely(wl->state == WL1271_STATE_OFF))
3903 goto out;
3904
Eliad Peller10c8cd02011-10-10 10:13:06 +02003905 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3906 goto out;
3907
Ido Yariva6208652011-03-01 15:14:41 +02003908 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003909 if (ret < 0)
3910 goto out;
3911
3912 if (is_ap)
3913 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3914 else
3915 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3916
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003917 wl1271_ps_elp_sleep(wl);
3918
3919out:
3920 mutex_unlock(&wl->mutex);
3921}
3922
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003923static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3924 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003925 const struct ieee80211_tx_queue_params *params)
3926{
3927 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003928 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003929 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003930 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003931
3932 mutex_lock(&wl->mutex);
3933
3934 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3935
Kalle Valo4695dc92010-03-18 12:26:38 +02003936 if (params->uapsd)
3937 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3938 else
3939 ps_scheme = CONF_PS_SCHEME_LEGACY;
3940
Arik Nemtsov488fc542010-10-16 20:33:45 +02003941 if (wl->state == WL1271_STATE_OFF) {
3942 /*
3943 * If the state is off, the parameters will be recorded and
3944 * configured on init. This happens in AP-mode.
3945 */
3946 struct conf_tx_ac_category *conf_ac =
3947 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3948 struct conf_tx_tid *conf_tid =
3949 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3950
3951 conf_ac->ac = wl1271_tx_get_queue(queue);
3952 conf_ac->cw_min = (u8)params->cw_min;
3953 conf_ac->cw_max = params->cw_max;
3954 conf_ac->aifsn = params->aifs;
3955 conf_ac->tx_op_limit = params->txop << 5;
3956
3957 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3958 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3959 conf_tid->tsid = wl1271_tx_get_queue(queue);
3960 conf_tid->ps_scheme = ps_scheme;
3961 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3962 conf_tid->apsd_conf[0] = 0;
3963 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003964 goto out;
3965 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003966
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003967 ret = wl1271_ps_elp_wakeup(wl);
3968 if (ret < 0)
3969 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003970
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003971 /*
3972 * the txop is confed in units of 32us by the mac80211,
3973 * we need us
3974 */
Eliad Peller0603d892011-10-05 11:55:51 +02003975 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003976 params->cw_min, params->cw_max,
3977 params->aifs, params->txop << 5);
3978 if (ret < 0)
3979 goto out_sleep;
3980
Eliad Peller0603d892011-10-05 11:55:51 +02003981 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003982 CONF_CHANNEL_TYPE_EDCF,
3983 wl1271_tx_get_queue(queue),
3984 ps_scheme, CONF_ACK_POLICY_LEGACY,
3985 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003986
3987out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003988 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003989
3990out:
3991 mutex_unlock(&wl->mutex);
3992
3993 return ret;
3994}
3995
Eliad Peller37a41b42011-09-21 14:06:11 +03003996static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
3997 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003998{
3999
4000 struct wl1271 *wl = hw->priv;
4001 u64 mactime = ULLONG_MAX;
4002 int ret;
4003
4004 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4005
4006 mutex_lock(&wl->mutex);
4007
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004008 if (unlikely(wl->state == WL1271_STATE_OFF))
4009 goto out;
4010
Ido Yariva6208652011-03-01 15:14:41 +02004011 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004012 if (ret < 0)
4013 goto out;
4014
4015 ret = wl1271_acx_tsf_info(wl, &mactime);
4016 if (ret < 0)
4017 goto out_sleep;
4018
4019out_sleep:
4020 wl1271_ps_elp_sleep(wl);
4021
4022out:
4023 mutex_unlock(&wl->mutex);
4024 return mactime;
4025}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004026
John W. Linvilleece550d2010-07-28 16:41:06 -04004027static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4028 struct survey_info *survey)
4029{
4030 struct wl1271 *wl = hw->priv;
4031 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004032
John W. Linvilleece550d2010-07-28 16:41:06 -04004033 if (idx != 0)
4034 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004035
John W. Linvilleece550d2010-07-28 16:41:06 -04004036 survey->channel = conf->channel;
4037 survey->filled = SURVEY_INFO_NOISE_DBM;
4038 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004039
John W. Linvilleece550d2010-07-28 16:41:06 -04004040 return 0;
4041}
4042
Arik Nemtsov409622e2011-02-23 00:22:29 +02004043static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004044 struct wl12xx_vif *wlvif,
4045 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004046{
4047 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004048 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004049
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004050
4051 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004052 wl1271_warning("could not allocate HLID - too much stations");
4053 return -EBUSY;
4054 }
4055
4056 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004057 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4058 if (ret < 0) {
4059 wl1271_warning("could not allocate HLID - too many links");
4060 return -EBUSY;
4061 }
4062
4063 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004064 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004065 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004066 return 0;
4067}
4068
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004069void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004070{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004071 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004072 return;
4073
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004074 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004075 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004076 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004077 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004078 __clear_bit(hlid, &wl->ap_ps_map);
4079 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004080 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004081 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004082}
4083
4084static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4085 struct ieee80211_vif *vif,
4086 struct ieee80211_sta *sta)
4087{
4088 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004089 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004090 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004091 int ret = 0;
4092 u8 hlid;
4093
4094 mutex_lock(&wl->mutex);
4095
4096 if (unlikely(wl->state == WL1271_STATE_OFF))
4097 goto out;
4098
Eliad Peller536129c2011-10-05 11:55:45 +02004099 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004100 goto out;
4101
4102 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4103
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004104 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004105 if (ret < 0)
4106 goto out;
4107
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004108 wl_sta = (struct wl1271_station *)sta->drv_priv;
4109 hlid = wl_sta->hlid;
4110
Ido Yariva6208652011-03-01 15:14:41 +02004111 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004112 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004113 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004114
Eliad Peller1b92f152011-10-10 10:13:09 +02004115 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004116 if (ret < 0)
4117 goto out_sleep;
4118
Eliad Pellerb67476e2011-08-14 13:17:23 +03004119 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4120 if (ret < 0)
4121 goto out_sleep;
4122
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004123 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4124 if (ret < 0)
4125 goto out_sleep;
4126
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004127out_sleep:
4128 wl1271_ps_elp_sleep(wl);
4129
Arik Nemtsov409622e2011-02-23 00:22:29 +02004130out_free_sta:
4131 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004132 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004133
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004134out:
4135 mutex_unlock(&wl->mutex);
4136 return ret;
4137}
4138
4139static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4140 struct ieee80211_vif *vif,
4141 struct ieee80211_sta *sta)
4142{
4143 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004144 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004145 struct wl1271_station *wl_sta;
4146 int ret = 0, id;
4147
4148 mutex_lock(&wl->mutex);
4149
4150 if (unlikely(wl->state == WL1271_STATE_OFF))
4151 goto out;
4152
Eliad Peller536129c2011-10-05 11:55:45 +02004153 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004154 goto out;
4155
4156 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4157
4158 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004159 id = wl_sta->hlid;
4160 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004161 goto out;
4162
Ido Yariva6208652011-03-01 15:14:41 +02004163 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004164 if (ret < 0)
4165 goto out;
4166
Eliad Pellerc690ec82011-08-14 13:17:07 +03004167 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004168 if (ret < 0)
4169 goto out_sleep;
4170
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004171 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004172
4173out_sleep:
4174 wl1271_ps_elp_sleep(wl);
4175
4176out:
4177 mutex_unlock(&wl->mutex);
4178 return ret;
4179}
4180
Luciano Coelho4623ec72011-03-21 19:26:41 +02004181static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4182 struct ieee80211_vif *vif,
4183 enum ieee80211_ampdu_mlme_action action,
4184 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4185 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004186{
4187 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004188 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004189 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004190 u8 hlid, *ba_bitmap;
4191
4192 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4193 tid);
4194
4195 /* sanity check - the fields in FW are only 8bits wide */
4196 if (WARN_ON(tid > 0xFF))
4197 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004198
4199 mutex_lock(&wl->mutex);
4200
4201 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4202 ret = -EAGAIN;
4203 goto out;
4204 }
4205
Eliad Peller536129c2011-10-05 11:55:45 +02004206 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004207 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004208 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004209 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004210 struct wl1271_station *wl_sta;
4211
4212 wl_sta = (struct wl1271_station *)sta->drv_priv;
4213 hlid = wl_sta->hlid;
4214 ba_bitmap = &wl->links[hlid].ba_bitmap;
4215 } else {
4216 ret = -EINVAL;
4217 goto out;
4218 }
4219
Ido Yariva6208652011-03-01 15:14:41 +02004220 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004221 if (ret < 0)
4222 goto out;
4223
Shahar Levi70559a02011-05-22 16:10:22 +03004224 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4225 tid, action);
4226
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004227 switch (action) {
4228 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004229 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004230 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004231 break;
4232 }
4233
4234 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4235 ret = -EBUSY;
4236 wl1271_error("exceeded max RX BA sessions");
4237 break;
4238 }
4239
4240 if (*ba_bitmap & BIT(tid)) {
4241 ret = -EINVAL;
4242 wl1271_error("cannot enable RX BA session on active "
4243 "tid: %d", tid);
4244 break;
4245 }
4246
4247 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4248 hlid);
4249 if (!ret) {
4250 *ba_bitmap |= BIT(tid);
4251 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004252 }
4253 break;
4254
4255 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004256 if (!(*ba_bitmap & BIT(tid))) {
4257 ret = -EINVAL;
4258 wl1271_error("no active RX BA session on tid: %d",
4259 tid);
4260 break;
4261 }
4262
4263 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4264 hlid);
4265 if (!ret) {
4266 *ba_bitmap &= ~BIT(tid);
4267 wl->ba_rx_session_count--;
4268 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004269 break;
4270
4271 /*
4272 * The BA initiator session management in FW independently.
4273 * Falling break here on purpose for all TX APDU commands.
4274 */
4275 case IEEE80211_AMPDU_TX_START:
4276 case IEEE80211_AMPDU_TX_STOP:
4277 case IEEE80211_AMPDU_TX_OPERATIONAL:
4278 ret = -EINVAL;
4279 break;
4280
4281 default:
4282 wl1271_error("Incorrect ampdu action id=%x\n", action);
4283 ret = -EINVAL;
4284 }
4285
4286 wl1271_ps_elp_sleep(wl);
4287
4288out:
4289 mutex_unlock(&wl->mutex);
4290
4291 return ret;
4292}
4293
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004294static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4295 struct ieee80211_vif *vif,
4296 const struct cfg80211_bitrate_mask *mask)
4297{
Eliad Peller83587502011-10-10 10:12:53 +02004298 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004299 struct wl1271 *wl = hw->priv;
4300 int i;
4301
4302 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4303 mask->control[NL80211_BAND_2GHZ].legacy,
4304 mask->control[NL80211_BAND_5GHZ].legacy);
4305
4306 mutex_lock(&wl->mutex);
4307
4308 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004309 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004310 wl1271_tx_enabled_rates_get(wl,
4311 mask->control[i].legacy,
4312 i);
4313 mutex_unlock(&wl->mutex);
4314
4315 return 0;
4316}
4317
Shahar Levi6d158ff2011-09-08 13:01:33 +03004318static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4319 struct ieee80211_channel_switch *ch_switch)
4320{
4321 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004322 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004323 int ret;
4324
4325 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4326
4327 mutex_lock(&wl->mutex);
4328
4329 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004330 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4331 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4332 ieee80211_chswitch_done(vif, false);
4333 }
4334 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004335 }
4336
4337 ret = wl1271_ps_elp_wakeup(wl);
4338 if (ret < 0)
4339 goto out;
4340
Eliad Peller52630c52011-10-10 10:13:08 +02004341 /* TODO: change mac80211 to pass vif as param */
4342 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4343 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004344
Eliad Peller52630c52011-10-10 10:13:08 +02004345 if (!ret)
4346 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4347 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004348
4349 wl1271_ps_elp_sleep(wl);
4350
4351out:
4352 mutex_unlock(&wl->mutex);
4353}
4354
Arik Nemtsov33437892011-04-26 23:35:39 +03004355static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4356{
4357 struct wl1271 *wl = hw->priv;
4358 bool ret = false;
4359
4360 mutex_lock(&wl->mutex);
4361
4362 if (unlikely(wl->state == WL1271_STATE_OFF))
4363 goto out;
4364
4365 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004366 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004367out:
4368 mutex_unlock(&wl->mutex);
4369
4370 return ret;
4371}
4372
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004373/* can't be const, mac80211 writes to this */
4374static struct ieee80211_rate wl1271_rates[] = {
4375 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004376 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4377 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004378 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004379 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4380 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004381 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4382 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004383 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4384 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004385 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4386 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004387 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4388 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004389 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4390 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004391 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4392 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004393 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004394 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4395 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004396 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004397 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4398 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004399 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004400 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4401 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004402 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004403 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4404 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004405 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004406 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4407 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004408 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004409 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4410 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004411 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004412 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4413 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004414};
4415
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004416/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004417static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004418 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004419 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004420 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4421 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4422 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004423 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004424 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4425 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4426 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004427 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004428 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4429 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4430 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004431 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004432};
4433
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004434/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004435static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004436 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004437 7, /* CONF_HW_RXTX_RATE_MCS7 */
4438 6, /* CONF_HW_RXTX_RATE_MCS6 */
4439 5, /* CONF_HW_RXTX_RATE_MCS5 */
4440 4, /* CONF_HW_RXTX_RATE_MCS4 */
4441 3, /* CONF_HW_RXTX_RATE_MCS3 */
4442 2, /* CONF_HW_RXTX_RATE_MCS2 */
4443 1, /* CONF_HW_RXTX_RATE_MCS1 */
4444 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004445
4446 11, /* CONF_HW_RXTX_RATE_54 */
4447 10, /* CONF_HW_RXTX_RATE_48 */
4448 9, /* CONF_HW_RXTX_RATE_36 */
4449 8, /* CONF_HW_RXTX_RATE_24 */
4450
4451 /* TI-specific rate */
4452 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4453
4454 7, /* CONF_HW_RXTX_RATE_18 */
4455 6, /* CONF_HW_RXTX_RATE_12 */
4456 3, /* CONF_HW_RXTX_RATE_11 */
4457 5, /* CONF_HW_RXTX_RATE_9 */
4458 4, /* CONF_HW_RXTX_RATE_6 */
4459 2, /* CONF_HW_RXTX_RATE_5_5 */
4460 1, /* CONF_HW_RXTX_RATE_2 */
4461 0 /* CONF_HW_RXTX_RATE_1 */
4462};
4463
Shahar Levie8b03a22010-10-13 16:09:39 +02004464/* 11n STA capabilities */
4465#define HW_RX_HIGHEST_RATE 72
4466
Shahar Levi00d20102010-11-08 11:20:10 +00004467#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004468 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4469 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004470 .ht_supported = true, \
4471 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4472 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4473 .mcs = { \
4474 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4475 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4476 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4477 }, \
4478}
4479
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004480/* can't be const, mac80211 writes to this */
4481static struct ieee80211_supported_band wl1271_band_2ghz = {
4482 .channels = wl1271_channels,
4483 .n_channels = ARRAY_SIZE(wl1271_channels),
4484 .bitrates = wl1271_rates,
4485 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004486 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004487};
4488
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004489/* 5 GHz data rates for WL1273 */
4490static struct ieee80211_rate wl1271_rates_5ghz[] = {
4491 { .bitrate = 60,
4492 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4493 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4494 { .bitrate = 90,
4495 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4496 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4497 { .bitrate = 120,
4498 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4499 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4500 { .bitrate = 180,
4501 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4502 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4503 { .bitrate = 240,
4504 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4505 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4506 { .bitrate = 360,
4507 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4508 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4509 { .bitrate = 480,
4510 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4511 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4512 { .bitrate = 540,
4513 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4514 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4515};
4516
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004517/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004518static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004519 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4520 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4521 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4522 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4523 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4524 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4525 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4526 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4527 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4528 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4529 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4530 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4531 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4532 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4533 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4534 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4535 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4536 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4537 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4538 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4539 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4540 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4541 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4542 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4543 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4544 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4545 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4546 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4547 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4548 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4549 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4550 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4551 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4552 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004553};
4554
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004555/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004556static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004557 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004558 7, /* CONF_HW_RXTX_RATE_MCS7 */
4559 6, /* CONF_HW_RXTX_RATE_MCS6 */
4560 5, /* CONF_HW_RXTX_RATE_MCS5 */
4561 4, /* CONF_HW_RXTX_RATE_MCS4 */
4562 3, /* CONF_HW_RXTX_RATE_MCS3 */
4563 2, /* CONF_HW_RXTX_RATE_MCS2 */
4564 1, /* CONF_HW_RXTX_RATE_MCS1 */
4565 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004566
4567 7, /* CONF_HW_RXTX_RATE_54 */
4568 6, /* CONF_HW_RXTX_RATE_48 */
4569 5, /* CONF_HW_RXTX_RATE_36 */
4570 4, /* CONF_HW_RXTX_RATE_24 */
4571
4572 /* TI-specific rate */
4573 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4574
4575 3, /* CONF_HW_RXTX_RATE_18 */
4576 2, /* CONF_HW_RXTX_RATE_12 */
4577 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4578 1, /* CONF_HW_RXTX_RATE_9 */
4579 0, /* CONF_HW_RXTX_RATE_6 */
4580 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4581 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4582 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4583};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004584
4585static struct ieee80211_supported_band wl1271_band_5ghz = {
4586 .channels = wl1271_channels_5ghz,
4587 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4588 .bitrates = wl1271_rates_5ghz,
4589 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004590 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004591};
4592
Tobias Klausera0ea9492010-05-20 10:38:11 +02004593static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004594 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4595 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4596};
4597
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004598static const struct ieee80211_ops wl1271_ops = {
4599 .start = wl1271_op_start,
4600 .stop = wl1271_op_stop,
4601 .add_interface = wl1271_op_add_interface,
4602 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004603#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004604 .suspend = wl1271_op_suspend,
4605 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004606#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004607 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004608 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004609 .configure_filter = wl1271_op_configure_filter,
4610 .tx = wl1271_op_tx,
4611 .set_key = wl1271_op_set_key,
4612 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004613 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004614 .sched_scan_start = wl1271_op_sched_scan_start,
4615 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004616 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004617 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004618 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004619 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004620 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004621 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004622 .sta_add = wl1271_op_sta_add,
4623 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004624 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004625 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004626 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004627 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004628 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004629};
4630
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004631
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004632u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004633{
4634 u8 idx;
4635
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004636 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004637
4638 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4639 wl1271_error("Illegal RX rate from HW: %d", rate);
4640 return 0;
4641 }
4642
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004643 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004644 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4645 wl1271_error("Unsupported RX rate from HW: %d", rate);
4646 return 0;
4647 }
4648
4649 return idx;
4650}
4651
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004652static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4653 struct device_attribute *attr,
4654 char *buf)
4655{
4656 struct wl1271 *wl = dev_get_drvdata(dev);
4657 ssize_t len;
4658
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004659 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004660
4661 mutex_lock(&wl->mutex);
4662 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4663 wl->sg_enabled);
4664 mutex_unlock(&wl->mutex);
4665
4666 return len;
4667
4668}
4669
4670static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4671 struct device_attribute *attr,
4672 const char *buf, size_t count)
4673{
4674 struct wl1271 *wl = dev_get_drvdata(dev);
4675 unsigned long res;
4676 int ret;
4677
Luciano Coelho6277ed62011-04-01 17:49:54 +03004678 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004679 if (ret < 0) {
4680 wl1271_warning("incorrect value written to bt_coex_mode");
4681 return count;
4682 }
4683
4684 mutex_lock(&wl->mutex);
4685
4686 res = !!res;
4687
4688 if (res == wl->sg_enabled)
4689 goto out;
4690
4691 wl->sg_enabled = res;
4692
4693 if (wl->state == WL1271_STATE_OFF)
4694 goto out;
4695
Ido Yariva6208652011-03-01 15:14:41 +02004696 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004697 if (ret < 0)
4698 goto out;
4699
4700 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4701 wl1271_ps_elp_sleep(wl);
4702
4703 out:
4704 mutex_unlock(&wl->mutex);
4705 return count;
4706}
4707
4708static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4709 wl1271_sysfs_show_bt_coex_state,
4710 wl1271_sysfs_store_bt_coex_state);
4711
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004712static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4713 struct device_attribute *attr,
4714 char *buf)
4715{
4716 struct wl1271 *wl = dev_get_drvdata(dev);
4717 ssize_t len;
4718
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004719 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004720
4721 mutex_lock(&wl->mutex);
4722 if (wl->hw_pg_ver >= 0)
4723 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4724 else
4725 len = snprintf(buf, len, "n/a\n");
4726 mutex_unlock(&wl->mutex);
4727
4728 return len;
4729}
4730
Gery Kahn6f07b722011-07-18 14:21:49 +03004731static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004732 wl1271_sysfs_show_hw_pg_ver, NULL);
4733
Ido Yariv95dac04f2011-06-06 14:57:06 +03004734static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4735 struct bin_attribute *bin_attr,
4736 char *buffer, loff_t pos, size_t count)
4737{
4738 struct device *dev = container_of(kobj, struct device, kobj);
4739 struct wl1271 *wl = dev_get_drvdata(dev);
4740 ssize_t len;
4741 int ret;
4742
4743 ret = mutex_lock_interruptible(&wl->mutex);
4744 if (ret < 0)
4745 return -ERESTARTSYS;
4746
4747 /* Let only one thread read the log at a time, blocking others */
4748 while (wl->fwlog_size == 0) {
4749 DEFINE_WAIT(wait);
4750
4751 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4752 &wait,
4753 TASK_INTERRUPTIBLE);
4754
4755 if (wl->fwlog_size != 0) {
4756 finish_wait(&wl->fwlog_waitq, &wait);
4757 break;
4758 }
4759
4760 mutex_unlock(&wl->mutex);
4761
4762 schedule();
4763 finish_wait(&wl->fwlog_waitq, &wait);
4764
4765 if (signal_pending(current))
4766 return -ERESTARTSYS;
4767
4768 ret = mutex_lock_interruptible(&wl->mutex);
4769 if (ret < 0)
4770 return -ERESTARTSYS;
4771 }
4772
4773 /* Check if the fwlog is still valid */
4774 if (wl->fwlog_size < 0) {
4775 mutex_unlock(&wl->mutex);
4776 return 0;
4777 }
4778
4779 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4780 len = min(count, (size_t)wl->fwlog_size);
4781 wl->fwlog_size -= len;
4782 memcpy(buffer, wl->fwlog, len);
4783
4784 /* Make room for new messages */
4785 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4786
4787 mutex_unlock(&wl->mutex);
4788
4789 return len;
4790}
4791
4792static struct bin_attribute fwlog_attr = {
4793 .attr = {.name = "fwlog", .mode = S_IRUSR},
4794 .read = wl1271_sysfs_read_fwlog,
4795};
4796
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004797int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004798{
4799 int ret;
4800
4801 if (wl->mac80211_registered)
4802 return 0;
4803
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004804 ret = wl1271_fetch_nvs(wl);
4805 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004806 /* NOTE: The wl->nvs->nvs element must be first, in
4807 * order to simplify the casting, we assume it is at
4808 * the beginning of the wl->nvs structure.
4809 */
4810 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004811
4812 wl->mac_addr[0] = nvs_ptr[11];
4813 wl->mac_addr[1] = nvs_ptr[10];
4814 wl->mac_addr[2] = nvs_ptr[6];
4815 wl->mac_addr[3] = nvs_ptr[5];
4816 wl->mac_addr[4] = nvs_ptr[4];
4817 wl->mac_addr[5] = nvs_ptr[3];
4818 }
4819
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004820 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4821
4822 ret = ieee80211_register_hw(wl->hw);
4823 if (ret < 0) {
4824 wl1271_error("unable to register mac80211 hw: %d", ret);
4825 return ret;
4826 }
4827
4828 wl->mac80211_registered = true;
4829
Eliad Pellerd60080a2010-11-24 12:53:16 +02004830 wl1271_debugfs_init(wl);
4831
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004832 register_netdevice_notifier(&wl1271_dev_notifier);
4833
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004834 wl1271_notice("loaded");
4835
4836 return 0;
4837}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004838EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004839
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004840void wl1271_unregister_hw(struct wl1271 *wl)
4841{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004842 if (wl->state == WL1271_STATE_PLT)
4843 __wl1271_plt_stop(wl);
4844
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004845 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004846 ieee80211_unregister_hw(wl->hw);
4847 wl->mac80211_registered = false;
4848
4849}
4850EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4851
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004852int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004853{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004854 static const u32 cipher_suites[] = {
4855 WLAN_CIPHER_SUITE_WEP40,
4856 WLAN_CIPHER_SUITE_WEP104,
4857 WLAN_CIPHER_SUITE_TKIP,
4858 WLAN_CIPHER_SUITE_CCMP,
4859 WL1271_CIPHER_SUITE_GEM,
4860 };
4861
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004862 /* The tx descriptor buffer and the TKIP space. */
4863 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4864 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004865
4866 /* unit us */
4867 /* FIXME: find a proper value */
4868 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004869 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004870
4871 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004872 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004873 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004874 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004875 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004876 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004877 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004878 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004879 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004880 IEEE80211_HW_AP_LINK_PS |
4881 IEEE80211_HW_AMPDU_AGGREGATION |
4882 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004883
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004884 wl->hw->wiphy->cipher_suites = cipher_suites;
4885 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4886
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004887 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004888 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4889 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004890 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004891 wl->hw->wiphy->max_sched_scan_ssids = 16;
4892 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004893 /*
4894 * Maximum length of elements in scanning probe request templates
4895 * should be the maximum length possible for a template, without
4896 * the IEEE80211 header of the template
4897 */
Eliad Peller154037d2011-08-14 13:17:12 +03004898 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004899 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004900
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004901 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4902 sizeof(struct ieee80211_header);
4903
Eliad Peller1ec23f72011-08-25 14:26:54 +03004904 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4905
Luciano Coelho4a31c112011-03-21 23:16:14 +02004906 /* make sure all our channels fit in the scanned_ch bitmask */
4907 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4908 ARRAY_SIZE(wl1271_channels_5ghz) >
4909 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004910 /*
4911 * We keep local copies of the band structs because we need to
4912 * modify them on a per-device basis.
4913 */
4914 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4915 sizeof(wl1271_band_2ghz));
4916 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4917 sizeof(wl1271_band_5ghz));
4918
4919 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4920 &wl->bands[IEEE80211_BAND_2GHZ];
4921 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4922 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004923
Kalle Valo12bd8942010-03-18 12:26:33 +02004924 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004925 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004926
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004927 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4928
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004929 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004930
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004931 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004932 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004933
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004934 wl->hw->max_rx_aggregation_subframes = 8;
4935
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004936 return 0;
4937}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004938EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004939
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004940#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004941
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004942struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004943{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004944 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004945 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004946 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004947 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004948 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004949
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004950 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004951
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004952 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4953 if (!hw) {
4954 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004955 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004956 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004957 }
4958
Julia Lawall929ebd32010-05-15 23:16:39 +02004959 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004960 if (!plat_dev) {
4961 wl1271_error("could not allocate platform_device");
4962 ret = -ENOMEM;
4963 goto err_plat_alloc;
4964 }
4965
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004966 wl = hw->priv;
4967 memset(wl, 0, sizeof(*wl));
4968
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004969 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02004970 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004971
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004972 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004973 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004974
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004975 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004976 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004977 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4978
Ido Yariva6208652011-03-01 15:14:41 +02004979 skb_queue_head_init(&wl->deferred_rx_queue);
4980 skb_queue_head_init(&wl->deferred_tx_queue);
4981
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004982 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02004983 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004984 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4985 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4986 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004987
Eliad Peller92ef8962011-06-07 12:50:46 +03004988 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4989 if (!wl->freezable_wq) {
4990 ret = -ENOMEM;
4991 goto err_hw;
4992 }
4993
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004994 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004995 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004996 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004997 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004998 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004999 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005000 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005001 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005002 wl->ap_ps_map = 0;
5003 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005004 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005005 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005006 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005007 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005008 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005009 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005010 wl->fwlog_size = 0;
5011 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005012
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005013 /* The system link is always allocated */
5014 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5015
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005016 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005017 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005018 wl->tx_frames[i] = NULL;
5019
5020 spin_lock_init(&wl->wl_lock);
5021
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005022 wl->state = WL1271_STATE_OFF;
5023 mutex_init(&wl->mutex);
5024
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005025 /* Apply default driver configuration. */
5026 wl1271_conf_init(wl);
5027
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005028 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5029 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5030 if (!wl->aggr_buf) {
5031 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005032 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005033 }
5034
Ido Yariv990f5de2011-03-31 10:06:59 +02005035 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5036 if (!wl->dummy_packet) {
5037 ret = -ENOMEM;
5038 goto err_aggr;
5039 }
5040
Ido Yariv95dac04f2011-06-06 14:57:06 +03005041 /* Allocate one page for the FW log */
5042 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5043 if (!wl->fwlog) {
5044 ret = -ENOMEM;
5045 goto err_dummy_packet;
5046 }
5047
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005048 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005049 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005050 if (ret) {
5051 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03005052 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005053 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005054 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005055
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005056 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005057 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005058 if (ret < 0) {
5059 wl1271_error("failed to create sysfs file bt_coex_state");
5060 goto err_platform;
5061 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005062
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005063 /* Create sysfs file to get HW PG version */
5064 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5065 if (ret < 0) {
5066 wl1271_error("failed to create sysfs file hw_pg_ver");
5067 goto err_bt_coex_state;
5068 }
5069
Ido Yariv95dac04f2011-06-06 14:57:06 +03005070 /* Create sysfs file for the FW log */
5071 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
5072 if (ret < 0) {
5073 wl1271_error("failed to create sysfs file fwlog");
5074 goto err_hw_pg_ver;
5075 }
5076
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005077 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005078
Ido Yariv95dac04f2011-06-06 14:57:06 +03005079err_hw_pg_ver:
5080 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5081
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005082err_bt_coex_state:
5083 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
5084
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005085err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005086 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005087
Ido Yariv95dac04f2011-06-06 14:57:06 +03005088err_fwlog:
5089 free_page((unsigned long)wl->fwlog);
5090
Ido Yariv990f5de2011-03-31 10:06:59 +02005091err_dummy_packet:
5092 dev_kfree_skb(wl->dummy_packet);
5093
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005094err_aggr:
5095 free_pages((unsigned long)wl->aggr_buf, order);
5096
Eliad Peller92ef8962011-06-07 12:50:46 +03005097err_wq:
5098 destroy_workqueue(wl->freezable_wq);
5099
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005100err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005101 wl1271_debugfs_exit(wl);
5102 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005103
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005104err_plat_alloc:
5105 ieee80211_free_hw(hw);
5106
5107err_hw_alloc:
5108
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005109 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005110}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005111EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005112
5113int wl1271_free_hw(struct wl1271 *wl)
5114{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005115 /* Unblock any fwlog readers */
5116 mutex_lock(&wl->mutex);
5117 wl->fwlog_size = -1;
5118 wake_up_interruptible_all(&wl->fwlog_waitq);
5119 mutex_unlock(&wl->mutex);
5120
5121 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005122
5123 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5124
5125 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005126 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005127 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005128 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005129 free_pages((unsigned long)wl->aggr_buf,
5130 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005131 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005132
5133 wl1271_debugfs_exit(wl);
5134
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005135 vfree(wl->fw);
5136 wl->fw = NULL;
5137 kfree(wl->nvs);
5138 wl->nvs = NULL;
5139
5140 kfree(wl->fw_status);
5141 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005142 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005143
5144 ieee80211_free_hw(wl->hw);
5145
5146 return 0;
5147}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005148EXPORT_SYMBOL_GPL(wl1271_free_hw);
5149
Guy Eilam491bbd62011-01-12 10:33:29 +01005150u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005151EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005152module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005153MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5154
Ido Yariv95dac04f2011-06-06 14:57:06 +03005155module_param_named(fwlog, fwlog_param, charp, 0);
5156MODULE_PARM_DESC(keymap,
5157 "FW logger options: continuous, ondemand, dbgpins or disable");
5158
Eliad Peller2a5bff02011-08-25 18:10:59 +03005159module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5160MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5161
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005162MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005163MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005164MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");