blob: 5137275d35913f7e71cf65b763e0527c796ae537 [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
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300782static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200783{
Arik Nemtsovda032092011-08-25 12:43:15 +0300784 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200785
Arik Nemtsovb622d992011-02-23 00:22:31 +0200786 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300787 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200788
789 /*
790 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300791 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200792 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300793 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200794 wl1271_ps_link_end(wl, hlid);
795
Arik Nemtsovda032092011-08-25 12:43:15 +0300796 /*
797 * Start high-level PS if the STA is asleep with enough blocks in FW.
798 * Make an exception if this is the only connected station. In this
799 * case FW-memory congestion is not a problem.
800 */
801 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200802 wl1271_ps_link_start(wl, hlid, true);
803}
804
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300805static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200806 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300807 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200808{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200809 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200810 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300811 u8 hlid, cnt;
812
813 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200814
815 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
816 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
817 wl1271_debug(DEBUG_PSM,
818 "link ps prev 0x%x cur 0x%x changed 0x%x",
819 wl->ap_fw_ps_map, cur_fw_ps_map,
820 wl->ap_fw_ps_map ^ cur_fw_ps_map);
821
822 wl->ap_fw_ps_map = cur_fw_ps_map;
823 }
824
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200825 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
826 lnk = &wl->links[hlid];
827 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200828
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200829 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
830 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200831
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200832 wl12xx_irq_ps_regulate_link(wl, hlid, lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200833 }
834}
835
Eliad Peller4d56ad92011-08-14 13:17:05 +0300836static void wl12xx_fw_status(struct wl1271 *wl,
837 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300838{
Eliad Peller536129c2011-10-05 11:55:45 +0200839 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
840 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200841 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200842 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300843 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300844 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300845
Eliad Peller4d56ad92011-08-14 13:17:05 +0300846 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200847
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300848 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
849 "drv_rx_counter = %d, tx_results_counter = %d)",
850 status->intr,
851 status->fw_rx_counter,
852 status->drv_rx_counter,
853 status->tx_results_counter);
854
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300855 for (i = 0; i < NUM_TX_QUEUES; i++) {
856 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300857 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300858 (status->tx_released_pkts[i] -
859 wl->tx_pkts_freed[i]) & 0xff;
860
861 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
862 }
863
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300864 /* prevent wrap-around in total blocks counter */
865 if (likely(wl->tx_blocks_freed <=
866 le32_to_cpu(status->total_released_blks)))
867 freed_blocks = le32_to_cpu(status->total_released_blks) -
868 wl->tx_blocks_freed;
869 else
870 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
871 le32_to_cpu(status->total_released_blks);
872
Eliad Peller4d56ad92011-08-14 13:17:05 +0300873 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200874
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300875 wl->tx_allocated_blocks -= freed_blocks;
876
Eliad Peller4d56ad92011-08-14 13:17:05 +0300877 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200878
Eliad Peller4d56ad92011-08-14 13:17:05 +0300879 /*
880 * The FW might change the total number of TX memblocks before
881 * we get a notification about blocks being released. Thus, the
882 * available blocks calculation might yield a temporary result
883 * which is lower than the actual available blocks. Keeping in
884 * mind that only blocks that were allocated can be moved from
885 * TX to RX, tx_blocks_available should never decrease here.
886 */
887 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
888 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300889
Ido Yariva5225502010-10-12 14:49:10 +0200890 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200891 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200892 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300893
Eliad Peller4d56ad92011-08-14 13:17:05 +0300894 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller536129c2011-10-05 11:55:45 +0200895 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200896 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller4d56ad92011-08-14 13:17:05 +0300897
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300898 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200899 getnstimeofday(&ts);
900 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
901 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902}
903
Ido Yariva6208652011-03-01 15:14:41 +0200904static void wl1271_flush_deferred_work(struct wl1271 *wl)
905{
906 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200907
Ido Yariva6208652011-03-01 15:14:41 +0200908 /* Pass all received frames to the network stack */
909 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
910 ieee80211_rx_ni(wl->hw, skb);
911
912 /* Return sent skbs to the network stack */
913 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300914 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200915}
916
917static void wl1271_netstack_work(struct work_struct *work)
918{
919 struct wl1271 *wl =
920 container_of(work, struct wl1271, netstack_work);
921
922 do {
923 wl1271_flush_deferred_work(wl);
924 } while (skb_queue_len(&wl->deferred_rx_queue));
925}
926
927#define WL1271_IRQ_MAX_LOOPS 256
928
929irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300930{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300932 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200933 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200934 struct wl1271 *wl = (struct wl1271 *)cookie;
935 bool done = false;
936 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200937 unsigned long flags;
938
939 /* TX might be handled here, avoid redundant work */
940 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
941 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300942
Ido Yariv341b7cd2011-03-31 10:07:01 +0200943 /*
944 * In case edge triggered interrupt must be used, we cannot iterate
945 * more than once without introducing race conditions with the hardirq.
946 */
947 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
948 loopcount = 1;
949
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300950 mutex_lock(&wl->mutex);
951
952 wl1271_debug(DEBUG_IRQ, "IRQ work");
953
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200954 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300955 goto out;
956
Ido Yariva6208652011-03-01 15:14:41 +0200957 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300958 if (ret < 0)
959 goto out;
960
Ido Yariva6208652011-03-01 15:14:41 +0200961 while (!done && loopcount--) {
962 /*
963 * In order to avoid a race with the hardirq, clear the flag
964 * before acknowledging the chip. Since the mutex is held,
965 * wl1271_ps_elp_wakeup cannot be called concurrently.
966 */
967 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
968 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200969
Eliad Peller4d56ad92011-08-14 13:17:05 +0300970 wl12xx_fw_status(wl, wl->fw_status);
971 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200972 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200973 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200974 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200975 continue;
976 }
977
Eliad Pellerccc83b02010-10-27 14:09:57 +0200978 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
979 wl1271_error("watchdog interrupt received! "
980 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300981 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200982
983 /* restarting the chip. ignore any other interrupt. */
984 goto out;
985 }
986
Ido Yariva6208652011-03-01 15:14:41 +0200987 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200988 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
989
Eliad Peller4d56ad92011-08-14 13:17:05 +0300990 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200991
Ido Yariva5225502010-10-12 14:49:10 +0200992 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200993 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200994 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300995 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200996 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200997 /*
998 * In order to avoid starvation of the TX path,
999 * call the work function directly.
1000 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001001 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +02001002 } else {
1003 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001004 }
1005
Ido Yariv8aad2462011-03-01 15:14:38 +02001006 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001007 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +02001008 (wl->tx_results_count & 0xff))
1009 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001010
1011 /* Make sure the deferred queues don't get too long */
1012 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1013 skb_queue_len(&wl->deferred_rx_queue);
1014 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1015 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001016 }
1017
1018 if (intr & WL1271_ACX_INTR_EVENT_A) {
1019 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1020 wl1271_event_handle(wl, 0);
1021 }
1022
1023 if (intr & WL1271_ACX_INTR_EVENT_B) {
1024 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1025 wl1271_event_handle(wl, 1);
1026 }
1027
1028 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1029 wl1271_debug(DEBUG_IRQ,
1030 "WL1271_ACX_INTR_INIT_COMPLETE");
1031
1032 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1033 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034 }
1035
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036 wl1271_ps_elp_sleep(wl);
1037
1038out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001039 spin_lock_irqsave(&wl->wl_lock, flags);
1040 /* In case TX was not handled here, queue TX work */
1041 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1042 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001043 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001044 ieee80211_queue_work(wl->hw, &wl->tx_work);
1045 spin_unlock_irqrestore(&wl->wl_lock, flags);
1046
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001048
1049 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050}
Ido Yariva6208652011-03-01 15:14:41 +02001051EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053static int wl1271_fetch_firmware(struct wl1271 *wl)
1054{
1055 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001056 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057 int ret;
1058
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001059 if (wl->chip.id == CHIP_ID_1283_PG20)
1060 fw_name = WL128X_FW_NAME;
1061 else
1062 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001063
1064 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1065
1066 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001067
1068 if (ret < 0) {
1069 wl1271_error("could not get firmware: %d", ret);
1070 return ret;
1071 }
1072
1073 if (fw->size % 4) {
1074 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1075 fw->size);
1076 ret = -EILSEQ;
1077 goto out;
1078 }
1079
Arik Nemtsov166d5042010-10-16 21:44:57 +02001080 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001082 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083
1084 if (!wl->fw) {
1085 wl1271_error("could not allocate memory for the firmware");
1086 ret = -ENOMEM;
1087 goto out;
1088 }
1089
1090 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001091 ret = 0;
1092
1093out:
1094 release_firmware(fw);
1095
1096 return ret;
1097}
1098
1099static int wl1271_fetch_nvs(struct wl1271 *wl)
1100{
1101 const struct firmware *fw;
1102 int ret;
1103
Shahar Levi5aa42342011-03-06 16:32:07 +02001104 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001105
1106 if (ret < 0) {
1107 wl1271_error("could not get nvs file: %d", ret);
1108 return ret;
1109 }
1110
Shahar Levibc765bf2011-03-06 16:32:10 +02001111 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001112
1113 if (!wl->nvs) {
1114 wl1271_error("could not allocate memory for the nvs file");
1115 ret = -ENOMEM;
1116 goto out;
1117 }
1118
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001119 wl->nvs_len = fw->size;
1120
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001121out:
1122 release_firmware(fw);
1123
1124 return ret;
1125}
1126
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001127void wl12xx_queue_recovery_work(struct wl1271 *wl)
1128{
1129 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1130 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1131}
1132
Ido Yariv95dac04f2011-06-06 14:57:06 +03001133size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1134{
1135 size_t len = 0;
1136
1137 /* The FW log is a length-value list, find where the log end */
1138 while (len < maxlen) {
1139 if (memblock[len] == 0)
1140 break;
1141 if (len + memblock[len] + 1 > maxlen)
1142 break;
1143 len += memblock[len] + 1;
1144 }
1145
1146 /* Make sure we have enough room */
1147 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1148
1149 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1150 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1151 wl->fwlog_size += len;
1152
1153 return len;
1154}
1155
1156static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1157{
1158 u32 addr;
1159 u32 first_addr;
1160 u8 *block;
1161
1162 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1163 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1164 (wl->conf.fwlog.mem_blocks == 0))
1165 return;
1166
1167 wl1271_info("Reading FW panic log");
1168
1169 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1170 if (!block)
1171 return;
1172
1173 /*
1174 * Make sure the chip is awake and the logger isn't active.
1175 * This might fail if the firmware hanged.
1176 */
1177 if (!wl1271_ps_elp_wakeup(wl))
1178 wl12xx_cmd_stop_fwlog(wl);
1179
1180 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001181 wl12xx_fw_status(wl, wl->fw_status);
1182 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001183 if (!first_addr)
1184 goto out;
1185
1186 /* Traverse the memory blocks linked list */
1187 addr = first_addr;
1188 do {
1189 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1190 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1191 false);
1192
1193 /*
1194 * Memory blocks are linked to one another. The first 4 bytes
1195 * of each memory block hold the hardware address of the next
1196 * one. The last memory block points to the first one.
1197 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001198 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001199 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1200 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1201 break;
1202 } while (addr && (addr != first_addr));
1203
1204 wake_up_interruptible(&wl->fwlog_waitq);
1205
1206out:
1207 kfree(block);
1208}
1209
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001210static void wl1271_recovery_work(struct work_struct *work)
1211{
1212 struct wl1271 *wl =
1213 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001214 struct wl12xx_vif *wlvif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001215
1216 mutex_lock(&wl->mutex);
1217
1218 if (wl->state != WL1271_STATE_ON)
1219 goto out;
1220
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001221 /* Avoid a recursive recovery */
1222 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1223
Ido Yariv95dac04f2011-06-06 14:57:06 +03001224 wl12xx_read_fwlog_panic(wl);
1225
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001226 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1227 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001228
Eliad Peller2a5bff02011-08-25 18:10:59 +03001229 BUG_ON(bug_on_recovery);
1230
Oz Krakowskib992c682011-06-26 10:36:02 +03001231 /*
1232 * Advance security sequence number to overcome potential progress
1233 * in the firmware during recovery. This doens't hurt if the network is
1234 * not encrypted.
1235 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001236 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001237 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001238 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001239 wlvif->tx_security_seq +=
1240 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1241 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001242
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001243 /* Prevent spurious TX during FW restart */
1244 ieee80211_stop_queues(wl->hw);
1245
Luciano Coelho33c2c062011-05-10 14:46:02 +03001246 if (wl->sched_scanning) {
1247 ieee80211_sched_scan_stopped(wl->hw);
1248 wl->sched_scanning = false;
1249 }
1250
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001251 /* reboot the chipset */
Eliad Peller536129c2011-10-05 11:55:45 +02001252 __wl1271_op_remove_interface(wl, wl->vif, false);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001253
1254 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1255
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001256 ieee80211_restart_hw(wl->hw);
1257
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001258 /*
1259 * Its safe to enable TX now - the queues are stopped after a request
1260 * to restart the HW.
1261 */
1262 ieee80211_wake_queues(wl->hw);
1263
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001264out:
1265 mutex_unlock(&wl->mutex);
1266}
1267
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001268static void wl1271_fw_wakeup(struct wl1271 *wl)
1269{
1270 u32 elp_reg;
1271
1272 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001273 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001274}
1275
1276static int wl1271_setup(struct wl1271 *wl)
1277{
1278 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1279 if (!wl->fw_status)
1280 return -ENOMEM;
1281
1282 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1283 if (!wl->tx_res_if) {
1284 kfree(wl->fw_status);
1285 return -ENOMEM;
1286 }
1287
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001288 return 0;
1289}
1290
1291static int wl1271_chip_wakeup(struct wl1271 *wl)
1292{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001293 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294 int ret = 0;
1295
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001296 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001297 ret = wl1271_power_on(wl);
1298 if (ret < 0)
1299 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001300 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001301 wl1271_io_reset(wl);
1302 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001303
1304 /* We don't need a real memory partition here, because we only want
1305 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001306 memset(&partition, 0, sizeof(partition));
1307 partition.reg.start = REGISTERS_BASE;
1308 partition.reg.size = REGISTERS_DOWN_SIZE;
1309 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001310
1311 /* ELP module wake up */
1312 wl1271_fw_wakeup(wl);
1313
1314 /* whal_FwCtrl_BootSm() */
1315
1316 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001317 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001318
1319 /* 1. check if chip id is valid */
1320
1321 switch (wl->chip.id) {
1322 case CHIP_ID_1271_PG10:
1323 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1324 wl->chip.id);
1325
1326 ret = wl1271_setup(wl);
1327 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001328 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329 break;
1330 case CHIP_ID_1271_PG20:
1331 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1332 wl->chip.id);
1333
1334 ret = wl1271_setup(wl);
1335 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001336 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001337 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001338 case CHIP_ID_1283_PG20:
1339 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1340 wl->chip.id);
1341
1342 ret = wl1271_setup(wl);
1343 if (ret < 0)
1344 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001345
Ido Yariv0da13da2011-03-31 10:06:58 +02001346 if (wl1271_set_block_size(wl))
1347 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001348 break;
1349 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001350 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001351 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001352 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001353 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001354 }
1355
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001356 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357 ret = wl1271_fetch_firmware(wl);
1358 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001359 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360 }
1361
1362 /* No NVS from netlink, try to get it from the filesystem */
1363 if (wl->nvs == NULL) {
1364 ret = wl1271_fetch_nvs(wl);
1365 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001366 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367 }
1368
1369out:
1370 return ret;
1371}
1372
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001373int wl1271_plt_start(struct wl1271 *wl)
1374{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001375 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001376 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001377 int ret;
1378
1379 mutex_lock(&wl->mutex);
1380
1381 wl1271_notice("power up");
1382
1383 if (wl->state != WL1271_STATE_OFF) {
1384 wl1271_error("cannot go into PLT state because not "
1385 "in off state: %d", wl->state);
1386 ret = -EBUSY;
1387 goto out;
1388 }
1389
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001390 while (retries) {
1391 retries--;
1392 ret = wl1271_chip_wakeup(wl);
1393 if (ret < 0)
1394 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001395
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001396 ret = wl1271_boot(wl);
1397 if (ret < 0)
1398 goto power_off;
1399
1400 ret = wl1271_plt_init(wl);
1401 if (ret < 0)
1402 goto irq_disable;
1403
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001404 wl->state = WL1271_STATE_PLT;
1405 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001406 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001407
Gery Kahn6f07b722011-07-18 14:21:49 +03001408 /* update hw/fw version info in wiphy struct */
1409 wiphy->hw_version = wl->chip.id;
1410 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1411 sizeof(wiphy->fw_version));
1412
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001413 goto out;
1414
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001415irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001416 mutex_unlock(&wl->mutex);
1417 /* Unlocking the mutex in the middle of handling is
1418 inherently unsafe. In this case we deem it safe to do,
1419 because we need to let any possibly pending IRQ out of
1420 the system (and while we are WL1271_STATE_OFF the IRQ
1421 work function will not do anything.) Also, any other
1422 possible concurrent operations will fail due to the
1423 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001424 wl1271_disable_interrupts(wl);
1425 wl1271_flush_deferred_work(wl);
1426 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001427 mutex_lock(&wl->mutex);
1428power_off:
1429 wl1271_power_off(wl);
1430 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001431
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001432 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1433 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001434out:
1435 mutex_unlock(&wl->mutex);
1436
1437 return ret;
1438}
1439
Luciano Coelho4623ec72011-03-21 19:26:41 +02001440static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441{
1442 int ret = 0;
1443
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444 wl1271_notice("power down");
1445
1446 if (wl->state != WL1271_STATE_PLT) {
1447 wl1271_error("cannot power down because not in PLT "
1448 "state: %d", wl->state);
1449 ret = -EBUSY;
1450 goto out;
1451 }
1452
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001453 wl1271_power_off(wl);
1454
1455 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001456 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001457
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001458 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001459 wl1271_disable_interrupts(wl);
1460 wl1271_flush_deferred_work(wl);
1461 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001462 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001463 mutex_lock(&wl->mutex);
1464out:
1465 return ret;
1466}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001467
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001468int wl1271_plt_stop(struct wl1271 *wl)
1469{
1470 int ret;
1471
1472 mutex_lock(&wl->mutex);
1473 ret = __wl1271_plt_stop(wl);
1474 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001475 return ret;
1476}
1477
Johannes Berg7bb45682011-02-24 14:42:06 +01001478static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001479{
1480 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001481 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1482 struct ieee80211_vif *vif = info->control.vif;
1483 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001484 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001485 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001486 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001487
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001488 mapping = skb_get_queue_mapping(skb);
1489 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001490
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001491 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001492
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001493 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001494
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001495 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001496 if (hlid == WL12XX_INVALID_LINK_ID ||
1497 !test_bit(hlid, wlvif->links_map)) {
1498 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
1499 dev_kfree_skb(skb);
1500 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001501 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001502
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001503 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1504 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1505
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001506 wl->tx_queue_count[q]++;
1507
1508 /*
1509 * The workqueue is slow to process the tx_queue and we need stop
1510 * the queue here, otherwise the queue will get too long.
1511 */
1512 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1513 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1514 ieee80211_stop_queue(wl->hw, mapping);
1515 set_bit(q, &wl->stopped_queues_map);
1516 }
1517
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001518 /*
1519 * The chip specific setup must run before the first TX packet -
1520 * before that, the tx_work will not be initialized!
1521 */
1522
Ido Yarivb07d4032011-03-01 15:14:43 +02001523 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1524 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001525 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001526
Arik Nemtsov04216da2011-08-14 13:17:38 +03001527out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001528 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001529}
1530
Shahar Leviae47c452011-03-06 16:32:14 +02001531int wl1271_tx_dummy_packet(struct wl1271 *wl)
1532{
Ido Yariv990f5de2011-03-31 10:06:59 +02001533 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001534 int q;
1535
1536 /* no need to queue a new dummy packet if one is already pending */
1537 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1538 return 0;
1539
1540 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001541
Ido Yariv990f5de2011-03-31 10:06:59 +02001542 spin_lock_irqsave(&wl->wl_lock, flags);
1543 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001544 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001545 spin_unlock_irqrestore(&wl->wl_lock, flags);
1546
1547 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1548 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001549 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001550
1551 /*
1552 * If the FW TX is busy, TX work will be scheduled by the threaded
1553 * interrupt handler function
1554 */
1555 return 0;
1556}
1557
1558/*
1559 * The size of the dummy packet should be at least 1400 bytes. However, in
1560 * order to minimize the number of bus transactions, aligning it to 512 bytes
1561 * boundaries could be beneficial, performance wise
1562 */
1563#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1564
Luciano Coelhocf27d862011-04-01 21:08:23 +03001565static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001566{
1567 struct sk_buff *skb;
1568 struct ieee80211_hdr_3addr *hdr;
1569 unsigned int dummy_packet_size;
1570
1571 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1572 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1573
1574 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001575 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001576 wl1271_warning("Failed to allocate a dummy packet skb");
1577 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001578 }
1579
1580 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1581
1582 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1583 memset(hdr, 0, sizeof(*hdr));
1584 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001585 IEEE80211_STYPE_NULLFUNC |
1586 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001587
Ido Yariv990f5de2011-03-31 10:06:59 +02001588 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001589
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001590 /* Dummy packets require the TID to be management */
1591 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001592
1593 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001594 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001595 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001596
Ido Yariv990f5de2011-03-31 10:06:59 +02001597 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001598}
1599
Ido Yariv990f5de2011-03-31 10:06:59 +02001600
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001601static struct notifier_block wl1271_dev_notifier = {
1602 .notifier_call = wl1271_dev_notify,
1603};
1604
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001605#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001606static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1607 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001608{
Eliad Pellere85d1622011-06-27 13:06:43 +03001609 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001610
Eliad Peller94390642011-05-13 11:57:13 +03001611 mutex_lock(&wl->mutex);
1612
Eliad Pellerba8447f2011-10-10 10:13:00 +02001613 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001614 goto out_unlock;
1615
Eliad Peller94390642011-05-13 11:57:13 +03001616 ret = wl1271_ps_elp_wakeup(wl);
1617 if (ret < 0)
1618 goto out_unlock;
1619
1620 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001621 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001622 DECLARE_COMPLETION_ONSTACK(compl);
1623
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001624 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001625 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001626 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001627 if (ret < 0)
1628 goto out_sleep;
1629
1630 /* we must unlock here so we will be able to get events */
1631 wl1271_ps_elp_sleep(wl);
1632 mutex_unlock(&wl->mutex);
1633
1634 ret = wait_for_completion_timeout(
1635 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1636 if (ret <= 0) {
1637 wl1271_warning("couldn't enter ps mode!");
1638 ret = -EBUSY;
1639 goto out;
1640 }
1641
1642 /* take mutex again, and wakeup */
1643 mutex_lock(&wl->mutex);
1644
1645 ret = wl1271_ps_elp_wakeup(wl);
1646 if (ret < 0)
1647 goto out_unlock;
1648 }
1649out_sleep:
1650 wl1271_ps_elp_sleep(wl);
1651out_unlock:
1652 mutex_unlock(&wl->mutex);
1653out:
1654 return ret;
1655
1656}
1657
Eliad Peller0603d892011-10-05 11:55:51 +02001658static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1659 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001660{
Eliad Pellere85d1622011-06-27 13:06:43 +03001661 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001662
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001663 mutex_lock(&wl->mutex);
1664
Eliad Peller53d40d02011-10-10 10:13:02 +02001665 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001666 goto out_unlock;
1667
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001668 ret = wl1271_ps_elp_wakeup(wl);
1669 if (ret < 0)
1670 goto out_unlock;
1671
Eliad Peller0603d892011-10-05 11:55:51 +02001672 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001673
1674 wl1271_ps_elp_sleep(wl);
1675out_unlock:
1676 mutex_unlock(&wl->mutex);
1677 return ret;
1678
1679}
1680
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001681static int wl1271_configure_suspend(struct wl1271 *wl,
1682 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001683{
Eliad Peller536129c2011-10-05 11:55:45 +02001684 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001685 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001686 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001687 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001688 return 0;
1689}
1690
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001691static void wl1271_configure_resume(struct wl1271 *wl,
1692 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001693{
1694 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001695 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1696 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001697
1698 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001699 return;
1700
1701 mutex_lock(&wl->mutex);
1702 ret = wl1271_ps_elp_wakeup(wl);
1703 if (ret < 0)
1704 goto out;
1705
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001706 if (is_sta) {
1707 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001708 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001709 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001710 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001711 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001712 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001713 }
Eliad Peller94390642011-05-13 11:57:13 +03001714
1715 wl1271_ps_elp_sleep(wl);
1716out:
1717 mutex_unlock(&wl->mutex);
1718}
1719
Eliad Peller402e48612011-05-13 11:57:09 +03001720static int wl1271_op_suspend(struct ieee80211_hw *hw,
1721 struct cfg80211_wowlan *wow)
1722{
1723 struct wl1271 *wl = hw->priv;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001724 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
1725 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001726 int ret;
1727
Eliad Peller402e48612011-05-13 11:57:09 +03001728 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001729 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001730
Eliad Peller4a859df2011-06-06 12:21:52 +03001731 wl->wow_enabled = true;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001732 ret = wl1271_configure_suspend(wl, wlvif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001733 if (ret < 0) {
1734 wl1271_warning("couldn't prepare device to suspend");
1735 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001736 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001737 /* flush any remaining work */
1738 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001739
1740 /*
1741 * disable and re-enable interrupts in order to flush
1742 * the threaded_irq
1743 */
1744 wl1271_disable_interrupts(wl);
1745
1746 /*
1747 * set suspended flag to avoid triggering a new threaded_irq
1748 * work. no need for spinlock as interrupts are disabled.
1749 */
1750 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1751
1752 wl1271_enable_interrupts(wl);
1753 flush_work(&wl->tx_work);
Eliad Peller252efa42011-10-05 11:56:00 +02001754 flush_delayed_work(&wlvif->pspoll_work);
Eliad Peller4a859df2011-06-06 12:21:52 +03001755 flush_delayed_work(&wl->elp_work);
1756
Eliad Peller402e48612011-05-13 11:57:09 +03001757 return 0;
1758}
1759
1760static int wl1271_op_resume(struct ieee80211_hw *hw)
1761{
1762 struct wl1271 *wl = hw->priv;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001763 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
1764 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001765 unsigned long flags;
1766 bool run_irq_work = false;
1767
Eliad Peller402e48612011-05-13 11:57:09 +03001768 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1769 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001770 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001771
1772 /*
1773 * re-enable irq_work enqueuing, and call irq_work directly if
1774 * there is a pending work.
1775 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001776 spin_lock_irqsave(&wl->wl_lock, flags);
1777 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1778 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1779 run_irq_work = true;
1780 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001781
Eliad Peller4a859df2011-06-06 12:21:52 +03001782 if (run_irq_work) {
1783 wl1271_debug(DEBUG_MAC80211,
1784 "run postponed irq_work directly");
1785 wl1271_irq(0, wl);
1786 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001787 }
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001788 wl1271_configure_resume(wl, wlvif);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001789 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001790
Eliad Peller402e48612011-05-13 11:57:09 +03001791 return 0;
1792}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001793#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001794
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001795static int wl1271_op_start(struct ieee80211_hw *hw)
1796{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001797 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1798
1799 /*
1800 * We have to delay the booting of the hardware because
1801 * we need to know the local MAC address before downloading and
1802 * initializing the firmware. The MAC address cannot be changed
1803 * after boot, and without the proper MAC address, the firmware
1804 * will not function properly.
1805 *
1806 * The MAC address is first known when the corresponding interface
1807 * is added. That is where we will initialize the hardware.
1808 */
1809
1810 return 0;
1811}
1812
1813static void wl1271_op_stop(struct ieee80211_hw *hw)
1814{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001815 struct wl1271 *wl = hw->priv;
1816 int i;
1817
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001818 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001819
Eliad Peller10c8cd02011-10-10 10:13:06 +02001820 mutex_lock(&wl->mutex);
1821 if (wl->state == WL1271_STATE_OFF) {
1822 mutex_unlock(&wl->mutex);
1823 return;
1824 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001825 /*
1826 * this must be before the cancel_work calls below, so that the work
1827 * functions don't perform further work.
1828 */
1829 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001830 mutex_unlock(&wl->mutex);
1831
1832 mutex_lock(&wl_list_mutex);
1833 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001834 mutex_unlock(&wl_list_mutex);
1835
1836 wl1271_disable_interrupts(wl);
1837 wl1271_flush_deferred_work(wl);
1838 cancel_delayed_work_sync(&wl->scan_complete_work);
1839 cancel_work_sync(&wl->netstack_work);
1840 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001841 cancel_delayed_work_sync(&wl->elp_work);
1842
1843 /* let's notify MAC80211 about the remaining pending TX frames */
1844 wl12xx_tx_reset(wl, true);
1845 mutex_lock(&wl->mutex);
1846
1847 wl1271_power_off(wl);
1848
1849 wl->band = IEEE80211_BAND_2GHZ;
1850
1851 wl->rx_counter = 0;
1852 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1853 wl->tx_blocks_available = 0;
1854 wl->tx_allocated_blocks = 0;
1855 wl->tx_results_count = 0;
1856 wl->tx_packets_count = 0;
1857 wl->time_offset = 0;
1858 wl->vif = NULL;
1859 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1860 wl->ap_fw_ps_map = 0;
1861 wl->ap_ps_map = 0;
1862 wl->sched_scanning = false;
1863 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1864 memset(wl->links_map, 0, sizeof(wl->links_map));
1865 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1866 wl->active_sta_count = 0;
1867
1868 /* The system link is always allocated */
1869 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1870
1871 /*
1872 * this is performed after the cancel_work calls and the associated
1873 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1874 * get executed before all these vars have been reset.
1875 */
1876 wl->flags = 0;
1877
1878 wl->tx_blocks_freed = 0;
1879
1880 for (i = 0; i < NUM_TX_QUEUES; i++) {
1881 wl->tx_pkts_freed[i] = 0;
1882 wl->tx_allocated_pkts[i] = 0;
1883 }
1884
1885 wl1271_debugfs_reset(wl);
1886
1887 kfree(wl->fw_status);
1888 wl->fw_status = NULL;
1889 kfree(wl->tx_res_if);
1890 wl->tx_res_if = NULL;
1891 kfree(wl->target_mem_map);
1892 wl->target_mem_map = NULL;
1893
1894 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001895}
1896
Eliad Peller536129c2011-10-05 11:55:45 +02001897static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001898{
Eliad Peller536129c2011-10-05 11:55:45 +02001899 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001900 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001901 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001902 return WL1271_ROLE_P2P_GO;
1903 else
1904 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001905
1906 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001907 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001908 return WL1271_ROLE_P2P_CL;
1909 else
1910 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001911
Eliad Peller227e81e2011-08-14 13:17:26 +03001912 case BSS_TYPE_IBSS:
1913 return WL1271_ROLE_IBSS;
1914
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001915 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001916 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001917 }
1918 return WL12XX_INVALID_ROLE_TYPE;
1919}
1920
Eliad Peller83587502011-10-10 10:12:53 +02001921static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001922{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001923 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
1924
Eliad Peller48e93e42011-10-10 10:12:58 +02001925 /* clear everything but the persistent data */
1926 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001927
1928 switch (ieee80211_vif_type_p2p(vif)) {
1929 case NL80211_IFTYPE_P2P_CLIENT:
1930 wlvif->p2p = 1;
1931 /* fall-through */
1932 case NL80211_IFTYPE_STATION:
1933 wlvif->bss_type = BSS_TYPE_STA_BSS;
1934 break;
1935 case NL80211_IFTYPE_ADHOC:
1936 wlvif->bss_type = BSS_TYPE_IBSS;
1937 break;
1938 case NL80211_IFTYPE_P2P_GO:
1939 wlvif->p2p = 1;
1940 /* fall-through */
1941 case NL80211_IFTYPE_AP:
1942 wlvif->bss_type = BSS_TYPE_AP_BSS;
1943 break;
1944 default:
1945 wlvif->bss_type = MAX_BSS_TYPE;
1946 return -EOPNOTSUPP;
1947 }
1948
Eliad Peller0603d892011-10-05 11:55:51 +02001949 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001950 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001951 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001952
Eliad Pellere936bbe2011-10-05 11:55:56 +02001953 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1954 wlvif->bss_type == BSS_TYPE_IBSS) {
1955 /* init sta/ibss data */
1956 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
1957
1958 } else {
1959 /* init ap data */
1960 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1961 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
1962 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001963
Eliad Peller83587502011-10-10 10:12:53 +02001964 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1965 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001966 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001967 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001968 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001969 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1970
Eliad Peller1b92f152011-10-10 10:13:09 +02001971 /*
1972 * mac80211 configures some values globally, while we treat them
1973 * per-interface. thus, on init, we have to copy them from wl
1974 */
1975 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001976 wlvif->channel = wl->channel;
Eliad Peller1b92f152011-10-10 10:13:09 +02001977
Eliad Peller9eb599e2011-10-10 10:12:59 +02001978 INIT_WORK(&wlvif->rx_streaming_enable_work,
1979 wl1271_rx_streaming_enable_work);
1980 INIT_WORK(&wlvif->rx_streaming_disable_work,
1981 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02001982 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02001983 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001984
Eliad Peller9eb599e2011-10-10 10:12:59 +02001985 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1986 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001987 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001988}
1989
Eliad Peller1d095472011-10-10 10:12:49 +02001990static bool wl12xx_init_fw(struct wl1271 *wl)
1991{
1992 int retries = WL1271_BOOT_RETRIES;
1993 bool booted = false;
1994 struct wiphy *wiphy = wl->hw->wiphy;
1995 int ret;
1996
1997 while (retries) {
1998 retries--;
1999 ret = wl1271_chip_wakeup(wl);
2000 if (ret < 0)
2001 goto power_off;
2002
2003 ret = wl1271_boot(wl);
2004 if (ret < 0)
2005 goto power_off;
2006
2007 ret = wl1271_hw_init(wl);
2008 if (ret < 0)
2009 goto irq_disable;
2010
2011 booted = true;
2012 break;
2013
2014irq_disable:
2015 mutex_unlock(&wl->mutex);
2016 /* Unlocking the mutex in the middle of handling is
2017 inherently unsafe. In this case we deem it safe to do,
2018 because we need to let any possibly pending IRQ out of
2019 the system (and while we are WL1271_STATE_OFF the IRQ
2020 work function will not do anything.) Also, any other
2021 possible concurrent operations will fail due to the
2022 current state, hence the wl1271 struct should be safe. */
2023 wl1271_disable_interrupts(wl);
2024 wl1271_flush_deferred_work(wl);
2025 cancel_work_sync(&wl->netstack_work);
2026 mutex_lock(&wl->mutex);
2027power_off:
2028 wl1271_power_off(wl);
2029 }
2030
2031 if (!booted) {
2032 wl1271_error("firmware boot failed despite %d retries",
2033 WL1271_BOOT_RETRIES);
2034 goto out;
2035 }
2036
2037 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2038
2039 /* update hw/fw version info in wiphy struct */
2040 wiphy->hw_version = wl->chip.id;
2041 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2042 sizeof(wiphy->fw_version));
2043
2044 /*
2045 * Now we know if 11a is supported (info from the NVS), so disable
2046 * 11a channels if not supported
2047 */
2048 if (!wl->enable_11a)
2049 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2050
2051 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2052 wl->enable_11a ? "" : "not ");
2053
2054 wl->state = WL1271_STATE_ON;
2055out:
2056 return booted;
2057}
2058
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002059static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2060 struct ieee80211_vif *vif)
2061{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002062 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002063 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002064 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002065 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002066 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002067
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002068 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002069 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002070
2071 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002072 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002073 wl1271_debug(DEBUG_MAC80211,
2074 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002075 ret = -EBUSY;
2076 goto out;
2077 }
2078
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002079 /*
2080 * in some very corner case HW recovery scenarios its possible to
2081 * get here before __wl1271_op_remove_interface is complete, so
2082 * opt out if that is the case.
2083 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002084 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2085 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002086 ret = -EBUSY;
2087 goto out;
2088 }
2089
Eliad Peller83587502011-10-10 10:12:53 +02002090 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002091 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002092 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002093
Eliad Peller252efa42011-10-05 11:56:00 +02002094 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002095 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002096 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2097 ret = -EINVAL;
2098 goto out;
2099 }
Eliad Peller1d095472011-10-10 10:12:49 +02002100
Eliad Peller784f6942011-10-05 11:55:39 +02002101 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002102 * TODO: after the nvs issue will be solved, move this block
2103 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002104 */
Eliad Peller1d095472011-10-10 10:12:49 +02002105 if (wl->state == WL1271_STATE_OFF) {
2106 /*
2107 * we still need this in order to configure the fw
2108 * while uploading the nvs
2109 */
2110 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002111
Eliad Peller1d095472011-10-10 10:12:49 +02002112 booted = wl12xx_init_fw(wl);
2113 if (!booted) {
2114 ret = -EINVAL;
2115 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002116 }
Eliad Peller1d095472011-10-10 10:12:49 +02002117 }
Eliad Peller04e80792011-08-14 13:17:09 +03002118
Eliad Peller1d095472011-10-10 10:12:49 +02002119 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2120 wlvif->bss_type == BSS_TYPE_IBSS) {
2121 /*
2122 * The device role is a special role used for
2123 * rx and tx frames prior to association (as
2124 * the STA role can get packets only from
2125 * its associated bssid)
2126 */
Eliad Peller784f6942011-10-05 11:55:39 +02002127 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002128 WL1271_ROLE_DEVICE,
2129 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002130 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002131 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002132 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002133
Eliad Peller1d095472011-10-10 10:12:49 +02002134 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2135 role_type, &wlvif->role_id);
2136 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002137 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002138
2139 ret = wl1271_init_vif_specific(wl, vif);
2140 if (ret < 0)
2141 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002142
2143 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002144 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002145 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002146
2147 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2148 wl->ap_count++;
2149 else
2150 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002151out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002152 mutex_unlock(&wl->mutex);
2153
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002154 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002155 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002156 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002157 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002158
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002159 return ret;
2160}
2161
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002162static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002163 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002164 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002165{
Eliad Peller536129c2011-10-05 11:55:45 +02002166 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002167 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002168
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002169 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002170
Eliad Peller10c8cd02011-10-10 10:13:06 +02002171 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2172 return;
2173
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002174 /* because of hardware recovery, we may get here twice */
2175 if (wl->state != WL1271_STATE_ON)
2176 return;
2177
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002178 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002179
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002180 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002181 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002182 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002183
Eliad Pellerbaf62772011-10-10 10:12:52 +02002184 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2185 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002186 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002187 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002188 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002189 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002190 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002191 }
2192
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002193 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2194 /* disable active roles */
2195 ret = wl1271_ps_elp_wakeup(wl);
2196 if (ret < 0)
2197 goto deinit;
2198
Eliad Peller536129c2011-10-05 11:55:45 +02002199 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002200 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002201 if (ret < 0)
2202 goto deinit;
2203 }
2204
Eliad Peller0603d892011-10-05 11:55:51 +02002205 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002206 if (ret < 0)
2207 goto deinit;
2208
2209 wl1271_ps_elp_sleep(wl);
2210 }
2211deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002212 /* clear all hlids (except system_hlid) */
Eliad Peller154da672011-10-05 11:55:53 +02002213 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002214 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002215 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2216 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002217
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002218 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002219 wl1271_free_ap_keys(wl, wlvif);
Eliad Peller87627212011-10-10 10:12:54 +02002220 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002221 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002222 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002223 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002224
Eliad Pellera4e41302011-10-11 11:49:15 +02002225 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2226 wl->ap_count--;
2227 else
2228 wl->sta_count--;
2229
Eliad Pellerbaf62772011-10-10 10:12:52 +02002230 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002231 del_timer_sync(&wlvif->rx_streaming_timer);
2232 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2233 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002234 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002235
Eliad Pellerbaf62772011-10-10 10:12:52 +02002236 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002237}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002238
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002239static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2240 struct ieee80211_vif *vif)
2241{
2242 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002243 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002244
2245 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002246
2247 if (wl->state == WL1271_STATE_OFF ||
2248 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2249 goto out;
2250
Juuso Oikarinen67353292010-11-18 15:19:02 +02002251 /*
2252 * wl->vif can be null here if someone shuts down the interface
2253 * just when hardware recovery has been started.
2254 */
2255 if (wl->vif) {
2256 WARN_ON(wl->vif != vif);
Eliad Peller536129c2011-10-05 11:55:45 +02002257 __wl1271_op_remove_interface(wl, vif, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002258 }
Eliad Peller10c8cd02011-10-10 10:13:06 +02002259out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002260 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002261 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002262}
2263
Eliad Peller87fbcb02011-10-05 11:55:41 +02002264static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2265 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002266{
2267 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002268 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002269
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002270 /*
2271 * One of the side effects of the JOIN command is that is clears
2272 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2273 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002274 * Currently the only valid scenario for JOIN during association
2275 * is on roaming, in which case we will also be given new keys.
2276 * Keep the below message for now, unless it starts bothering
2277 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002278 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002279 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002280 wl1271_info("JOIN while associated.");
2281
2282 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002283 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002284
Eliad Peller227e81e2011-08-14 13:17:26 +03002285 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002286 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002287 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002288 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002289 if (ret < 0)
2290 goto out;
2291
Eliad Pellerba8447f2011-10-10 10:13:00 +02002292 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002293 goto out;
2294
2295 /*
2296 * The join command disable the keep-alive mode, shut down its process,
2297 * and also clear the template config, so we need to reset it all after
2298 * the join. The acx_aid starts the keep-alive process, and the order
2299 * of the commands below is relevant.
2300 */
Eliad Peller0603d892011-10-05 11:55:51 +02002301 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002302 if (ret < 0)
2303 goto out;
2304
Eliad Peller0603d892011-10-05 11:55:51 +02002305 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002306 if (ret < 0)
2307 goto out;
2308
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002309 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002310 if (ret < 0)
2311 goto out;
2312
Eliad Peller0603d892011-10-05 11:55:51 +02002313 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2314 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002315 ACX_KEEP_ALIVE_TPL_VALID);
2316 if (ret < 0)
2317 goto out;
2318
2319out:
2320 return ret;
2321}
2322
Eliad Peller0603d892011-10-05 11:55:51 +02002323static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002324{
2325 int ret;
2326
Eliad Peller52630c52011-10-10 10:13:08 +02002327 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Shahar Levi6d158ff2011-09-08 13:01:33 +03002328 wl12xx_cmd_stop_channel_switch(wl);
2329 ieee80211_chswitch_done(wl->vif, false);
2330 }
2331
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002332 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002333 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002334 if (ret < 0)
2335 goto out;
2336
Oz Krakowskib992c682011-06-26 10:36:02 +03002337 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002338 wlvif->tx_security_last_seq_lsb = 0;
2339 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002340
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002341out:
2342 return ret;
2343}
2344
Eliad Peller87fbcb02011-10-05 11:55:41 +02002345static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002346{
Eliad Peller1b92f152011-10-10 10:13:09 +02002347 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002348 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002349}
2350
Eliad Peller251c1772011-08-14 13:17:17 +03002351static bool wl12xx_is_roc(struct wl1271 *wl)
2352{
2353 u8 role_id;
2354
2355 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2356 if (role_id >= WL12XX_MAX_ROLES)
2357 return false;
2358
2359 return true;
2360}
2361
Eliad Peller87fbcb02011-10-05 11:55:41 +02002362static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2363 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002364{
2365 int ret;
2366
2367 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002368 /* no need to croc if we weren't busy (e.g. during boot) */
2369 if (wl12xx_is_roc(wl)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002370 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002371 if (ret < 0)
2372 goto out;
2373
Eliad Peller7edebf52011-10-05 11:55:52 +02002374 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002375 if (ret < 0)
2376 goto out;
2377 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002378 wlvif->rate_set =
2379 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2380 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002381 if (ret < 0)
2382 goto out;
2383 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002384 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002385 ACX_KEEP_ALIVE_TPL_INVALID);
2386 if (ret < 0)
2387 goto out;
2388 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2389 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002390 /* The current firmware only supports sched_scan in idle */
2391 if (wl->sched_scanning) {
2392 wl1271_scan_sched_scan_stop(wl);
2393 ieee80211_sched_scan_stopped(wl->hw);
2394 }
2395
Eliad Peller7edebf52011-10-05 11:55:52 +02002396 ret = wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002397 if (ret < 0)
2398 goto out;
2399
Eliad Peller1b92f152011-10-10 10:13:09 +02002400 ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002401 if (ret < 0)
2402 goto out;
2403 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2404 }
2405
2406out:
2407 return ret;
2408}
2409
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002410static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2411{
2412 struct wl1271 *wl = hw->priv;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002413 struct ieee80211_vif *vif = wl->vif; /* TODO: reconfig all vifs */
2414 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002415 struct ieee80211_conf *conf = &hw->conf;
2416 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002417 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002418
2419 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2420
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002421 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2422 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002423 channel,
2424 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002425 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002426 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2427 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002428
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002429 /*
2430 * mac80211 will go to idle nearly immediately after transmitting some
2431 * frames, such as the deauth. To make sure those frames reach the air,
2432 * wait here until the TX queue is fully flushed.
2433 */
2434 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2435 (conf->flags & IEEE80211_CONF_IDLE))
2436 wl1271_tx_flush(wl);
2437
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002438 mutex_lock(&wl->mutex);
2439
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002440 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002441 /* we support configuring the channel and band while off */
2442 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2443 wl->band = conf->channel->band;
2444 wl->channel = channel;
2445 }
2446
Arik Nemtsov097f8822011-06-27 22:06:34 +03002447 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2448 wl->power_level = conf->power_level;
2449
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002450 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002451 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002452
Eliad Peller536129c2011-10-05 11:55:45 +02002453 is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002454
Ido Yariva6208652011-03-01 15:14:41 +02002455 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002456 if (ret < 0)
2457 goto out;
2458
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002459 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002460 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002461 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002462 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002463 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002464 wl1271_tx_work_locked(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002465 wl->band = conf->channel->band;
2466 wl->channel = channel;
Eliad Peller61f845f2011-10-10 10:13:10 +02002467 wlvif->band = conf->channel->band;
2468 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002469
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002470 if (!is_ap) {
2471 /*
2472 * FIXME: the mac80211 should really provide a fixed
2473 * rate to use here. for now, just use the smallest
2474 * possible rate for the band as a fixed rate for
2475 * association frames and other control messages.
2476 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002477 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002478 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002479
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002480 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002481 wl1271_tx_min_rate_get(wl,
2482 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002483 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002484 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002485 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002486 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002487
Eliad Pellerba8447f2011-10-10 10:13:00 +02002488 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2489 &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002490 if (wl12xx_is_roc(wl)) {
2491 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002492 ret = wl12xx_croc(wl,
2493 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002494 if (ret < 0)
2495 goto out_sleep;
2496 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002497 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002498 if (ret < 0)
2499 wl1271_warning("cmd join on channel "
2500 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002501 } else {
2502 /*
2503 * change the ROC channel. do it only if we are
2504 * not idle. otherwise, CROC will be called
2505 * anyway.
2506 */
2507 if (wl12xx_is_roc(wl) &&
2508 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002509 ret = wl12xx_croc(wl,
2510 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002511 if (ret < 0)
2512 goto out_sleep;
2513
Eliad Peller1b92f152011-10-10 10:13:09 +02002514 ret = wl12xx_roc(wl, wlvif,
Eliad Peller7edebf52011-10-05 11:55:52 +02002515 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002516 if (ret < 0)
2517 wl1271_warning("roc failed %d",
2518 ret);
2519 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002520 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002521 }
2522 }
2523
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002524 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002525 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002526 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002527 if (ret < 0)
2528 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002529 }
2530
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002531 /*
2532 * if mac80211 changes the PSM mode, make sure the mode is not
2533 * incorrectly changed after the pspoll failure active window.
2534 */
2535 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002536 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002537
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002538 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002539 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2540 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002541
2542 /*
2543 * We enter PSM only if we're already associated.
2544 * If we're not, we'll enter it when joining an SSID,
2545 * through the bss_info_changed() hook.
2546 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002547 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002548 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002549 ret = wl1271_ps_set_mode(wl, wlvif,
2550 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002551 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002552 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002553 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002554 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002555 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002556
Eliad Pellerc29bb002011-10-10 10:13:03 +02002557 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002558
Eliad Pellerc29bb002011-10-10 10:13:03 +02002559 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002560 ret = wl1271_ps_set_mode(wl, wlvif,
2561 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002562 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002563 }
2564
2565 if (conf->power_level != wl->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002566 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002567 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002568 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002569
2570 wl->power_level = conf->power_level;
2571 }
2572
2573out_sleep:
2574 wl1271_ps_elp_sleep(wl);
2575
2576out:
2577 mutex_unlock(&wl->mutex);
2578
2579 return ret;
2580}
2581
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002582struct wl1271_filter_params {
2583 bool enabled;
2584 int mc_list_length;
2585 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2586};
2587
Jiri Pirko22bedad2010-04-01 21:22:57 +00002588static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2589 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002590{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002591 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002592 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002593 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002594
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002595 if (unlikely(wl->state == WL1271_STATE_OFF))
2596 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002597
Juuso Oikarinen74441132009-10-13 12:47:53 +03002598 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002599 if (!fp) {
2600 wl1271_error("Out of memory setting filters.");
2601 return 0;
2602 }
2603
2604 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002605 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002606 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2607 fp->enabled = false;
2608 } else {
2609 fp->enabled = true;
2610 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002611 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002612 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002613 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002614 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002615 }
2616
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002617 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002618}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002619
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002620#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2621 FIF_ALLMULTI | \
2622 FIF_FCSFAIL | \
2623 FIF_BCN_PRBRESP_PROMISC | \
2624 FIF_CONTROL | \
2625 FIF_OTHER_BSS)
2626
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002627static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2628 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002629 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002630{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002631 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002632 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002633 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
2634 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2635
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002636 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002637
Arik Nemtsov7d057862010-10-16 19:25:35 +02002638 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2639 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002640
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002641 mutex_lock(&wl->mutex);
2642
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002643 *total &= WL1271_SUPPORTED_FILTERS;
2644 changed &= WL1271_SUPPORTED_FILTERS;
2645
2646 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002647 goto out;
2648
Ido Yariva6208652011-03-01 15:14:41 +02002649 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002650 if (ret < 0)
2651 goto out;
2652
Eliad Peller536129c2011-10-05 11:55:45 +02002653 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
Arik Nemtsov7d057862010-10-16 19:25:35 +02002654 if (*total & FIF_ALLMULTI)
Eliad Peller0603d892011-10-05 11:55:51 +02002655 ret = wl1271_acx_group_address_tbl(wl, wlvif, false,
2656 NULL, 0);
Arik Nemtsov7d057862010-10-16 19:25:35 +02002657 else if (fp)
Eliad Peller0603d892011-10-05 11:55:51 +02002658 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2659 fp->enabled,
Arik Nemtsov7d057862010-10-16 19:25:35 +02002660 fp->mc_list,
2661 fp->mc_list_length);
2662 if (ret < 0)
2663 goto out_sleep;
2664 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002665
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002666 /*
2667 * the fw doesn't provide an api to configure the filters. instead,
2668 * the filters configuration is based on the active roles / ROC
2669 * state.
2670 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002671
2672out_sleep:
2673 wl1271_ps_elp_sleep(wl);
2674
2675out:
2676 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002677 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002678}
2679
Eliad Peller170d0e62011-10-05 11:56:06 +02002680static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2681 u8 id, u8 key_type, u8 key_size,
2682 const u8 *key, u8 hlid, u32 tx_seq_32,
2683 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002684{
2685 struct wl1271_ap_key *ap_key;
2686 int i;
2687
2688 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2689
2690 if (key_size > MAX_KEY_SIZE)
2691 return -EINVAL;
2692
2693 /*
2694 * Find next free entry in ap_keys. Also check we are not replacing
2695 * an existing key.
2696 */
2697 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002698 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002699 break;
2700
Eliad Peller170d0e62011-10-05 11:56:06 +02002701 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002702 wl1271_warning("trying to record key replacement");
2703 return -EINVAL;
2704 }
2705 }
2706
2707 if (i == MAX_NUM_KEYS)
2708 return -EBUSY;
2709
2710 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2711 if (!ap_key)
2712 return -ENOMEM;
2713
2714 ap_key->id = id;
2715 ap_key->key_type = key_type;
2716 ap_key->key_size = key_size;
2717 memcpy(ap_key->key, key, key_size);
2718 ap_key->hlid = hlid;
2719 ap_key->tx_seq_32 = tx_seq_32;
2720 ap_key->tx_seq_16 = tx_seq_16;
2721
Eliad Peller170d0e62011-10-05 11:56:06 +02002722 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002723 return 0;
2724}
2725
Eliad Peller170d0e62011-10-05 11:56:06 +02002726static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002727{
2728 int i;
2729
2730 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002731 kfree(wlvif->ap.recorded_keys[i]);
2732 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002733 }
2734}
2735
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002736static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002737{
2738 int i, ret = 0;
2739 struct wl1271_ap_key *key;
2740 bool wep_key_added = false;
2741
2742 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002743 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002744 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002745 break;
2746
Eliad Peller170d0e62011-10-05 11:56:06 +02002747 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002748 hlid = key->hlid;
2749 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002750 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002751
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002752 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002753 key->id, key->key_type,
2754 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002755 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002756 key->tx_seq_16);
2757 if (ret < 0)
2758 goto out;
2759
2760 if (key->key_type == KEY_WEP)
2761 wep_key_added = true;
2762 }
2763
2764 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002765 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002766 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002767 if (ret < 0)
2768 goto out;
2769 }
2770
2771out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002772 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002773 return ret;
2774}
2775
Eliad Peller536129c2011-10-05 11:55:45 +02002776static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2777 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002778 u8 key_size, const u8 *key, u32 tx_seq_32,
2779 u16 tx_seq_16, struct ieee80211_sta *sta)
2780{
2781 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002782 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002783
2784 if (is_ap) {
2785 struct wl1271_station *wl_sta;
2786 u8 hlid;
2787
2788 if (sta) {
2789 wl_sta = (struct wl1271_station *)sta->drv_priv;
2790 hlid = wl_sta->hlid;
2791 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002792 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002793 }
2794
Eliad Peller53d40d02011-10-10 10:13:02 +02002795 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002796 /*
2797 * We do not support removing keys after AP shutdown.
2798 * Pretend we do to make mac80211 happy.
2799 */
2800 if (action != KEY_ADD_OR_REPLACE)
2801 return 0;
2802
Eliad Peller170d0e62011-10-05 11:56:06 +02002803 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002804 key_type, key_size,
2805 key, hlid, tx_seq_32,
2806 tx_seq_16);
2807 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002808 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002809 id, key_type, key_size,
2810 key, hlid, tx_seq_32,
2811 tx_seq_16);
2812 }
2813
2814 if (ret < 0)
2815 return ret;
2816 } else {
2817 const u8 *addr;
2818 static const u8 bcast_addr[ETH_ALEN] = {
2819 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2820 };
2821
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002822 /*
2823 * A STA set to GEM cipher requires 2 tx spare blocks.
2824 * Return to default value when GEM cipher key is removed
2825 */
2826 if (key_type == KEY_GEM) {
2827 if (action == KEY_ADD_OR_REPLACE)
2828 wl->tx_spare_blocks = 2;
2829 else if (action == KEY_REMOVE)
2830 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2831 }
2832
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002833 addr = sta ? sta->addr : bcast_addr;
2834
2835 if (is_zero_ether_addr(addr)) {
2836 /* We dont support TX only encryption */
2837 return -EOPNOTSUPP;
2838 }
2839
2840 /* The wl1271 does not allow to remove unicast keys - they
2841 will be cleared automatically on next CMD_JOIN. Ignore the
2842 request silently, as we dont want the mac80211 to emit
2843 an error message. */
2844 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2845 return 0;
2846
Eliad Peller010d3d32011-08-14 13:17:31 +03002847 /* don't remove key if hlid was already deleted */
2848 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002849 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002850 return 0;
2851
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002852 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002853 id, key_type, key_size,
2854 key, addr, tx_seq_32,
2855 tx_seq_16);
2856 if (ret < 0)
2857 return ret;
2858
2859 /* the default WEP key needs to be configured at least once */
2860 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002861 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002862 wlvif->default_key,
2863 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002864 if (ret < 0)
2865 return ret;
2866 }
2867 }
2868
2869 return 0;
2870}
2871
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002872static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2873 struct ieee80211_vif *vif,
2874 struct ieee80211_sta *sta,
2875 struct ieee80211_key_conf *key_conf)
2876{
2877 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002878 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002879 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002880 u32 tx_seq_32 = 0;
2881 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002882 u8 key_type;
2883
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002884 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2885
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002886 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002887 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002888 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002889 key_conf->keylen, key_conf->flags);
2890 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2891
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002892 mutex_lock(&wl->mutex);
2893
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002894 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2895 ret = -EAGAIN;
2896 goto out_unlock;
2897 }
2898
Ido Yariva6208652011-03-01 15:14:41 +02002899 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002900 if (ret < 0)
2901 goto out_unlock;
2902
Johannes Berg97359d12010-08-10 09:46:38 +02002903 switch (key_conf->cipher) {
2904 case WLAN_CIPHER_SUITE_WEP40:
2905 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002906 key_type = KEY_WEP;
2907
2908 key_conf->hw_key_idx = key_conf->keyidx;
2909 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002910 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002911 key_type = KEY_TKIP;
2912
2913 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002914 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2915 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002916 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002917 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002918 key_type = KEY_AES;
2919
2920 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Eliad Peller48e93e42011-10-10 10:12:58 +02002921 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2922 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002923 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002924 case WL1271_CIPHER_SUITE_GEM:
2925 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002926 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2927 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002928 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002929 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002930 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002931
2932 ret = -EOPNOTSUPP;
2933 goto out_sleep;
2934 }
2935
2936 switch (cmd) {
2937 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002938 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002939 key_conf->keyidx, key_type,
2940 key_conf->keylen, key_conf->key,
2941 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002942 if (ret < 0) {
2943 wl1271_error("Could not add or replace key");
2944 goto out_sleep;
2945 }
2946 break;
2947
2948 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002949 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002950 key_conf->keyidx, key_type,
2951 key_conf->keylen, key_conf->key,
2952 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002953 if (ret < 0) {
2954 wl1271_error("Could not remove key");
2955 goto out_sleep;
2956 }
2957 break;
2958
2959 default:
2960 wl1271_error("Unsupported key cmd 0x%x", cmd);
2961 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002962 break;
2963 }
2964
2965out_sleep:
2966 wl1271_ps_elp_sleep(wl);
2967
2968out_unlock:
2969 mutex_unlock(&wl->mutex);
2970
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002971 return ret;
2972}
2973
2974static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002975 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002976 struct cfg80211_scan_request *req)
2977{
2978 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02002979 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2980
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002981 int ret;
2982 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002983 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002984
2985 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2986
2987 if (req->n_ssids) {
2988 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002989 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002990 }
2991
2992 mutex_lock(&wl->mutex);
2993
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002994 if (wl->state == WL1271_STATE_OFF) {
2995 /*
2996 * We cannot return -EBUSY here because cfg80211 will expect
2997 * a call to ieee80211_scan_completed if we do - in this case
2998 * there won't be any call.
2999 */
3000 ret = -EAGAIN;
3001 goto out;
3002 }
3003
Ido Yariva6208652011-03-01 15:14:41 +02003004 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003005 if (ret < 0)
3006 goto out;
3007
Eliad Peller251c1772011-08-14 13:17:17 +03003008 /* cancel ROC before scanning */
3009 if (wl12xx_is_roc(wl)) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02003010 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03003011 /* don't allow scanning right now */
3012 ret = -EBUSY;
3013 goto out_sleep;
3014 }
Eliad Peller7edebf52011-10-05 11:55:52 +02003015 wl12xx_croc(wl, wlvif->dev_role_id);
3016 wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003017 }
3018
Eliad Peller784f6942011-10-05 11:55:39 +02003019 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003020out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003021 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003022out:
3023 mutex_unlock(&wl->mutex);
3024
3025 return ret;
3026}
3027
Eliad Peller73ecce32011-06-27 13:06:45 +03003028static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3029 struct ieee80211_vif *vif)
3030{
3031 struct wl1271 *wl = hw->priv;
3032 int ret;
3033
3034 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3035
3036 mutex_lock(&wl->mutex);
3037
3038 if (wl->state == WL1271_STATE_OFF)
3039 goto out;
3040
3041 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3042 goto out;
3043
3044 ret = wl1271_ps_elp_wakeup(wl);
3045 if (ret < 0)
3046 goto out;
3047
3048 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3049 ret = wl1271_scan_stop(wl);
3050 if (ret < 0)
3051 goto out_sleep;
3052 }
3053 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3054 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003055 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003056 wl->scan.req = NULL;
3057 ieee80211_scan_completed(wl->hw, true);
3058
3059out_sleep:
3060 wl1271_ps_elp_sleep(wl);
3061out:
3062 mutex_unlock(&wl->mutex);
3063
3064 cancel_delayed_work_sync(&wl->scan_complete_work);
3065}
3066
Luciano Coelho33c2c062011-05-10 14:46:02 +03003067static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3068 struct ieee80211_vif *vif,
3069 struct cfg80211_sched_scan_request *req,
3070 struct ieee80211_sched_scan_ies *ies)
3071{
3072 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003073 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003074 int ret;
3075
3076 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3077
3078 mutex_lock(&wl->mutex);
3079
3080 ret = wl1271_ps_elp_wakeup(wl);
3081 if (ret < 0)
3082 goto out;
3083
Eliad Peller536129c2011-10-05 11:55:45 +02003084 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003085 if (ret < 0)
3086 goto out_sleep;
3087
Eliad Peller536129c2011-10-05 11:55:45 +02003088 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003089 if (ret < 0)
3090 goto out_sleep;
3091
3092 wl->sched_scanning = true;
3093
3094out_sleep:
3095 wl1271_ps_elp_sleep(wl);
3096out:
3097 mutex_unlock(&wl->mutex);
3098 return ret;
3099}
3100
3101static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3102 struct ieee80211_vif *vif)
3103{
3104 struct wl1271 *wl = hw->priv;
3105 int ret;
3106
3107 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3108
3109 mutex_lock(&wl->mutex);
3110
3111 ret = wl1271_ps_elp_wakeup(wl);
3112 if (ret < 0)
3113 goto out;
3114
3115 wl1271_scan_sched_scan_stop(wl);
3116
3117 wl1271_ps_elp_sleep(wl);
3118out:
3119 mutex_unlock(&wl->mutex);
3120}
3121
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003122static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3123{
3124 struct wl1271 *wl = hw->priv;
3125 int ret = 0;
3126
3127 mutex_lock(&wl->mutex);
3128
3129 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3130 ret = -EAGAIN;
3131 goto out;
3132 }
3133
Ido Yariva6208652011-03-01 15:14:41 +02003134 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003135 if (ret < 0)
3136 goto out;
3137
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003138 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003139 if (ret < 0)
3140 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3141
3142 wl1271_ps_elp_sleep(wl);
3143
3144out:
3145 mutex_unlock(&wl->mutex);
3146
3147 return ret;
3148}
3149
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003150static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3151{
3152 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003153 struct ieee80211_vif *vif = wl->vif;
3154 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003155 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003156
3157 mutex_lock(&wl->mutex);
3158
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003159 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3160 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003161 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003162 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003163
Ido Yariva6208652011-03-01 15:14:41 +02003164 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003165 if (ret < 0)
3166 goto out;
3167
Eliad Peller0603d892011-10-05 11:55:51 +02003168 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003169 if (ret < 0)
3170 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
3171
3172 wl1271_ps_elp_sleep(wl);
3173
3174out:
3175 mutex_unlock(&wl->mutex);
3176
3177 return ret;
3178}
3179
Eliad Peller1fe9f162011-10-05 11:55:48 +02003180static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003181 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003182{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003183 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003184 u8 ssid_len;
3185 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3186 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003187
Eliad Peller889cb362011-05-01 09:56:45 +03003188 if (!ptr) {
3189 wl1271_error("No SSID in IEs!");
3190 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003191 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003192
Eliad Peller889cb362011-05-01 09:56:45 +03003193 ssid_len = ptr[1];
3194 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3195 wl1271_error("SSID is too long!");
3196 return -EINVAL;
3197 }
3198
Eliad Peller1fe9f162011-10-05 11:55:48 +02003199 wlvif->ssid_len = ssid_len;
3200 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003201 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003202}
3203
Eliad Pellerd48055d2011-09-15 12:07:04 +03003204static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3205{
3206 int len;
3207 const u8 *next, *end = skb->data + skb->len;
3208 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3209 skb->len - ieoffset);
3210 if (!ie)
3211 return;
3212 len = ie[1] + 2;
3213 next = ie + len;
3214 memmove(ie, next, end - next);
3215 skb_trim(skb, skb->len - len);
3216}
3217
Eliad Peller26b4bf22011-09-15 12:07:05 +03003218static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3219 unsigned int oui, u8 oui_type,
3220 int ieoffset)
3221{
3222 int len;
3223 const u8 *next, *end = skb->data + skb->len;
3224 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3225 skb->data + ieoffset,
3226 skb->len - ieoffset);
3227 if (!ie)
3228 return;
3229 len = ie[1] + 2;
3230 next = ie + len;
3231 memmove(ie, next, end - next);
3232 skb_trim(skb, skb->len - len);
3233}
3234
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003235static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
Eliad Peller1fe9f162011-10-05 11:55:48 +02003236 struct ieee80211_vif *vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003237 u8 *probe_rsp_data,
3238 size_t probe_rsp_len,
3239 u32 rates)
3240{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003241 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3242 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003243 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3244 int ssid_ie_offset, ie_offset, templ_len;
3245 const u8 *ptr;
3246
3247 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003248 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003249 return wl1271_cmd_template_set(wl,
3250 CMD_TEMPL_AP_PROBE_RESPONSE,
3251 probe_rsp_data,
3252 probe_rsp_len, 0,
3253 rates);
3254
3255 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3256 wl1271_error("probe_rsp template too big");
3257 return -EINVAL;
3258 }
3259
3260 /* start searching from IE offset */
3261 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3262
3263 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3264 probe_rsp_len - ie_offset);
3265 if (!ptr) {
3266 wl1271_error("No SSID in beacon!");
3267 return -EINVAL;
3268 }
3269
3270 ssid_ie_offset = ptr - probe_rsp_data;
3271 ptr += (ptr[1] + 2);
3272
3273 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3274
3275 /* insert SSID from bss_conf */
3276 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3277 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3278 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3279 bss_conf->ssid, bss_conf->ssid_len);
3280 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3281
3282 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3283 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3284 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3285
3286 return wl1271_cmd_template_set(wl,
3287 CMD_TEMPL_AP_PROBE_RESPONSE,
3288 probe_rsp_templ,
3289 templ_len, 0,
3290 rates);
3291}
3292
Arik Nemtsove78a2872010-10-16 19:07:21 +02003293static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003294 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003295 struct ieee80211_bss_conf *bss_conf,
3296 u32 changed)
3297{
Eliad Peller0603d892011-10-05 11:55:51 +02003298 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003299 int ret = 0;
3300
3301 if (changed & BSS_CHANGED_ERP_SLOT) {
3302 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003303 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003304 else
Eliad Peller0603d892011-10-05 11:55:51 +02003305 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003306 if (ret < 0) {
3307 wl1271_warning("Set slot time failed %d", ret);
3308 goto out;
3309 }
3310 }
3311
3312 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3313 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003314 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003315 else
Eliad Peller0603d892011-10-05 11:55:51 +02003316 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003317 }
3318
3319 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3320 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003321 ret = wl1271_acx_cts_protect(wl, wlvif,
3322 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003323 else
Eliad Peller0603d892011-10-05 11:55:51 +02003324 ret = wl1271_acx_cts_protect(wl, wlvif,
3325 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003326 if (ret < 0) {
3327 wl1271_warning("Set ctsprotect failed %d", ret);
3328 goto out;
3329 }
3330 }
3331
3332out:
3333 return ret;
3334}
3335
3336static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3337 struct ieee80211_vif *vif,
3338 struct ieee80211_bss_conf *bss_conf,
3339 u32 changed)
3340{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003341 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003342 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003343 int ret = 0;
3344
3345 if ((changed & BSS_CHANGED_BEACON_INT)) {
3346 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3347 bss_conf->beacon_int);
3348
Eliad Peller6a899792011-10-05 11:55:58 +02003349 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003350 }
3351
3352 if ((changed & BSS_CHANGED_BEACON)) {
3353 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003354 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003355 int ieoffset = offsetof(struct ieee80211_mgmt,
3356 u.beacon.variable);
3357 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3358 u16 tmpl_id;
3359
3360 if (!beacon)
3361 goto out;
3362
3363 wl1271_debug(DEBUG_MASTER, "beacon updated");
3364
Eliad Peller1fe9f162011-10-05 11:55:48 +02003365 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003366 if (ret < 0) {
3367 dev_kfree_skb(beacon);
3368 goto out;
3369 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003370 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003371 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3372 CMD_TEMPL_BEACON;
3373 ret = wl1271_cmd_template_set(wl, tmpl_id,
3374 beacon->data,
3375 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003376 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003377 if (ret < 0) {
3378 dev_kfree_skb(beacon);
3379 goto out;
3380 }
3381
Eliad Pellerd48055d2011-09-15 12:07:04 +03003382 /* remove TIM ie from probe response */
3383 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3384
Eliad Peller26b4bf22011-09-15 12:07:05 +03003385 /*
3386 * remove p2p ie from probe response.
3387 * the fw reponds to probe requests that don't include
3388 * the p2p ie. probe requests with p2p ie will be passed,
3389 * and will be responded by the supplicant (the spec
3390 * forbids including the p2p ie when responding to probe
3391 * requests that didn't include it).
3392 */
3393 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3394 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3395
Arik Nemtsove78a2872010-10-16 19:07:21 +02003396 hdr = (struct ieee80211_hdr *) beacon->data;
3397 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3398 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003399 if (is_ap)
Eliad Peller1fe9f162011-10-05 11:55:48 +02003400 ret = wl1271_ap_set_probe_resp_tmpl(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003401 beacon->data,
3402 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003403 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003404 else
3405 ret = wl1271_cmd_template_set(wl,
3406 CMD_TEMPL_PROBE_RESPONSE,
3407 beacon->data,
3408 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003409 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003410 dev_kfree_skb(beacon);
3411 if (ret < 0)
3412 goto out;
3413 }
3414
3415out:
3416 return ret;
3417}
3418
3419/* AP mode changes */
3420static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003421 struct ieee80211_vif *vif,
3422 struct ieee80211_bss_conf *bss_conf,
3423 u32 changed)
3424{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003425 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003426 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003427
Arik Nemtsove78a2872010-10-16 19:07:21 +02003428 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3429 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003430
Eliad Peller87fbcb02011-10-05 11:55:41 +02003431 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003432 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003433 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003434 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003435
Eliad Peller87fbcb02011-10-05 11:55:41 +02003436 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003437 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003438 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003439 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003440 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003441
Eliad Peller784f6942011-10-05 11:55:39 +02003442 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003443 if (ret < 0)
3444 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003445 }
3446
Arik Nemtsove78a2872010-10-16 19:07:21 +02003447 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3448 if (ret < 0)
3449 goto out;
3450
3451 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3452 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003453 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003454 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003455 if (ret < 0)
3456 goto out;
3457
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003458 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003459 if (ret < 0)
3460 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003461
Eliad Peller53d40d02011-10-10 10:13:02 +02003462 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003463 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003464 }
3465 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003466 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003467 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003468 if (ret < 0)
3469 goto out;
3470
Eliad Peller53d40d02011-10-10 10:13:02 +02003471 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003472 wl1271_debug(DEBUG_AP, "stopped AP");
3473 }
3474 }
3475 }
3476
Eliad Peller0603d892011-10-05 11:55:51 +02003477 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003478 if (ret < 0)
3479 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003480
3481 /* Handle HT information change */
3482 if ((changed & BSS_CHANGED_HT) &&
3483 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003484 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003485 bss_conf->ht_operation_mode);
3486 if (ret < 0) {
3487 wl1271_warning("Set ht information failed %d", ret);
3488 goto out;
3489 }
3490 }
3491
Arik Nemtsove78a2872010-10-16 19:07:21 +02003492out:
3493 return;
3494}
3495
3496/* STA/IBSS mode changes */
3497static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3498 struct ieee80211_vif *vif,
3499 struct ieee80211_bss_conf *bss_conf,
3500 u32 changed)
3501{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003502 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003503 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003504 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003505 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003506 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003507 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003508 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003509 bool sta_exists = false;
3510 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003511
3512 if (is_ibss) {
3513 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3514 changed);
3515 if (ret < 0)
3516 goto out;
3517 }
3518
Eliad Peller227e81e2011-08-14 13:17:26 +03003519 if (changed & BSS_CHANGED_IBSS) {
3520 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003521 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003522 ibss_joined = true;
3523 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003524 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3525 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003526 wl1271_unjoin(wl, wlvif);
Eliad Peller7edebf52011-10-05 11:55:52 +02003527 wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller1b92f152011-10-10 10:13:09 +02003528 wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
Eliad Peller227e81e2011-08-14 13:17:26 +03003529 }
3530 }
3531 }
3532
3533 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003534 do_join = true;
3535
3536 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003537 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003538 do_join = true;
3539
Eliad Peller227e81e2011-08-14 13:17:26 +03003540 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003541 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3542 bss_conf->enable_beacon ? "enabled" : "disabled");
3543
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003544 do_join = true;
3545 }
3546
Arik Nemtsove78a2872010-10-16 19:07:21 +02003547 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003548 bool enable = false;
3549 if (bss_conf->cqm_rssi_thold)
3550 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003551 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003552 bss_conf->cqm_rssi_thold,
3553 bss_conf->cqm_rssi_hyst);
3554 if (ret < 0)
3555 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003556 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003557 }
3558
Eliad Pellercdf09492011-10-05 11:55:44 +02003559 if (changed & BSS_CHANGED_BSSID)
3560 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003561 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003562 if (ret < 0)
3563 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003564
Eliad Peller784f6942011-10-05 11:55:39 +02003565 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003566 if (ret < 0)
3567 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003568
Eliad Pellerfa287b82010-12-26 09:27:50 +01003569 /* Need to update the BSSID (for filtering etc) */
3570 do_join = true;
3571 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003572
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003573 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3574 rcu_read_lock();
3575 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3576 if (!sta)
3577 goto sta_not_found;
3578
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003579 /* save the supp_rates of the ap */
3580 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3581 if (sta->ht_cap.ht_supported)
3582 sta_rate_set |=
3583 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003584 sta_ht_cap = sta->ht_cap;
3585 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003586
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003587sta_not_found:
3588 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003589 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003590
Arik Nemtsove78a2872010-10-16 19:07:21 +02003591 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003592 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003593 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003594 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003595 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003596 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003597
Eliad Peller74ec8392011-10-05 11:56:02 +02003598 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003599
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003600 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003601 * use basic rates from AP, and determine lowest rate
3602 * to use with control frames.
3603 */
3604 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003605 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003606 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003607 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003608 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003609 wl1271_tx_min_rate_get(wl,
3610 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003611 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003612 wlvif->rate_set =
3613 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003614 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003615 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003616 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003617 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003618 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003619
3620 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003621 * with wl1271, we don't need to update the
3622 * beacon_int and dtim_period, because the firmware
3623 * updates it by itself when the first beacon is
3624 * received after a join.
3625 */
Eliad Peller6840e372011-10-05 11:55:50 +02003626 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003627 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003628 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003629
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003630 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003631 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003632 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003633 dev_kfree_skb(wlvif->probereq);
3634 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003635 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003636 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003637 ieoffset = offsetof(struct ieee80211_mgmt,
3638 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003639 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003640
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003641 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003642 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003643 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003644 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003645 } else {
3646 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003647 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003648 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3649 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003650 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003651 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3652 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003653 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003654
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003655 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003656 dev_kfree_skb(wlvif->probereq);
3657 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003658
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003659 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003660 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003661
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003662 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003663 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003664 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003665 wl1271_tx_min_rate_get(wl,
3666 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003667 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003668 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003669 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003670
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003671 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003672 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003673
3674 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003675 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003676 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003677 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003678
3679 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003680 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003681 u32 conf_flags = wl->hw->conf.flags;
3682 /*
3683 * we might have to disable roc, if there was
3684 * no IF_OPER_UP notification.
3685 */
3686 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003687 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003688 if (ret < 0)
3689 goto out;
3690 }
3691 /*
3692 * (we also need to disable roc in case of
3693 * roaming on the same channel. until we will
3694 * have a better flow...)
3695 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003696 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3697 ret = wl12xx_croc(wl,
3698 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003699 if (ret < 0)
3700 goto out;
3701 }
3702
Eliad Peller0603d892011-10-05 11:55:51 +02003703 wl1271_unjoin(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003704 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02003705 wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller1b92f152011-10-10 10:13:09 +02003706 wl12xx_roc(wl, wlvif,
3707 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003708 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003709 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003710 }
3711 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003712
Eliad Pellerd192d262011-05-24 14:33:08 +03003713 if (changed & BSS_CHANGED_IBSS) {
3714 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3715 bss_conf->ibss_joined);
3716
3717 if (bss_conf->ibss_joined) {
3718 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003719 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003720 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003721 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003722 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003723 wl1271_tx_min_rate_get(wl,
3724 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003725
Shahar Levi06b660e2011-09-05 13:54:36 +03003726 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003727 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3728 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003729 if (ret < 0)
3730 goto out;
3731 }
3732 }
3733
Eliad Peller0603d892011-10-05 11:55:51 +02003734 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003735 if (ret < 0)
3736 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003737
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003738 if (changed & BSS_CHANGED_ARP_FILTER) {
3739 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003740 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003741
Eliad Pellerc5312772010-12-09 11:31:27 +02003742 if (bss_conf->arp_addr_cnt == 1 &&
3743 bss_conf->arp_filter_enabled) {
3744 /*
3745 * The template should have been configured only upon
3746 * association. however, it seems that the correct ip
3747 * isn't being set (when sending), so we have to
3748 * reconfigure the template upon every ip change.
3749 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003750 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003751 if (ret < 0) {
3752 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003753 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003754 }
3755
Eliad Peller0603d892011-10-05 11:55:51 +02003756 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003757 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003758 addr);
3759 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003760 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003761
3762 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003763 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003764 }
3765
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003766 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003767 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003768 if (ret < 0) {
3769 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003770 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003771 }
Eliad Peller251c1772011-08-14 13:17:17 +03003772
3773 /* ROC until connected (after EAPOL exchange) */
3774 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003775 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003776 if (ret < 0)
3777 goto out;
3778
Eliad Pellerba8447f2011-10-10 10:13:00 +02003779 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003780 ieee80211_get_operstate(vif));
3781 }
3782 /*
3783 * stop device role if started (we might already be in
3784 * STA role). TODO: make it better.
3785 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003786 if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3787 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003788 if (ret < 0)
3789 goto out;
3790
Eliad Peller7edebf52011-10-05 11:55:52 +02003791 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003792 if (ret < 0)
3793 goto out;
3794 }
Eliad Peller05dba352011-08-23 16:37:01 +03003795
3796 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003797 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3798 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003799 enum wl1271_cmd_ps_mode mode;
3800
3801 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003802 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003803 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003804 true);
3805 if (ret < 0)
3806 goto out;
3807 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003808 }
3809
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003810 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003811 if (sta_exists) {
3812 if ((changed & BSS_CHANGED_HT) &&
3813 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003814 ret = wl1271_acx_set_ht_capabilities(wl,
3815 &sta_ht_cap,
3816 true,
Eliad Peller154da672011-10-05 11:55:53 +02003817 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003818 if (ret < 0) {
3819 wl1271_warning("Set ht cap true failed %d",
3820 ret);
3821 goto out;
3822 }
3823 }
3824 /* handle new association without HT and disassociation */
3825 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003826 ret = wl1271_acx_set_ht_capabilities(wl,
3827 &sta_ht_cap,
3828 false,
Eliad Peller154da672011-10-05 11:55:53 +02003829 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003830 if (ret < 0) {
3831 wl1271_warning("Set ht cap false failed %d",
3832 ret);
3833 goto out;
3834 }
3835 }
3836 }
3837
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003838 /* Handle HT information change. Done after join. */
3839 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003840 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003841 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003842 bss_conf->ht_operation_mode);
3843 if (ret < 0) {
3844 wl1271_warning("Set ht information failed %d", ret);
3845 goto out;
3846 }
3847 }
3848
Arik Nemtsove78a2872010-10-16 19:07:21 +02003849out:
3850 return;
3851}
3852
3853static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3854 struct ieee80211_vif *vif,
3855 struct ieee80211_bss_conf *bss_conf,
3856 u32 changed)
3857{
3858 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003859 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3860 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003861 int ret;
3862
3863 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3864 (int)changed);
3865
3866 mutex_lock(&wl->mutex);
3867
3868 if (unlikely(wl->state == WL1271_STATE_OFF))
3869 goto out;
3870
Eliad Peller10c8cd02011-10-10 10:13:06 +02003871 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3872 goto out;
3873
Ido Yariva6208652011-03-01 15:14:41 +02003874 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003875 if (ret < 0)
3876 goto out;
3877
3878 if (is_ap)
3879 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3880 else
3881 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3882
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003883 wl1271_ps_elp_sleep(wl);
3884
3885out:
3886 mutex_unlock(&wl->mutex);
3887}
3888
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003889static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3890 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003891 const struct ieee80211_tx_queue_params *params)
3892{
3893 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003894 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003895 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003896 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003897
3898 mutex_lock(&wl->mutex);
3899
3900 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3901
Kalle Valo4695dc92010-03-18 12:26:38 +02003902 if (params->uapsd)
3903 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3904 else
3905 ps_scheme = CONF_PS_SCHEME_LEGACY;
3906
Arik Nemtsov488fc542010-10-16 20:33:45 +02003907 if (wl->state == WL1271_STATE_OFF) {
3908 /*
3909 * If the state is off, the parameters will be recorded and
3910 * configured on init. This happens in AP-mode.
3911 */
3912 struct conf_tx_ac_category *conf_ac =
3913 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3914 struct conf_tx_tid *conf_tid =
3915 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3916
3917 conf_ac->ac = wl1271_tx_get_queue(queue);
3918 conf_ac->cw_min = (u8)params->cw_min;
3919 conf_ac->cw_max = params->cw_max;
3920 conf_ac->aifsn = params->aifs;
3921 conf_ac->tx_op_limit = params->txop << 5;
3922
3923 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3924 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3925 conf_tid->tsid = wl1271_tx_get_queue(queue);
3926 conf_tid->ps_scheme = ps_scheme;
3927 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3928 conf_tid->apsd_conf[0] = 0;
3929 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003930 goto out;
3931 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003932
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003933 ret = wl1271_ps_elp_wakeup(wl);
3934 if (ret < 0)
3935 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003936
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003937 /*
3938 * the txop is confed in units of 32us by the mac80211,
3939 * we need us
3940 */
Eliad Peller0603d892011-10-05 11:55:51 +02003941 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003942 params->cw_min, params->cw_max,
3943 params->aifs, params->txop << 5);
3944 if (ret < 0)
3945 goto out_sleep;
3946
Eliad Peller0603d892011-10-05 11:55:51 +02003947 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003948 CONF_CHANNEL_TYPE_EDCF,
3949 wl1271_tx_get_queue(queue),
3950 ps_scheme, CONF_ACK_POLICY_LEGACY,
3951 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003952
3953out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003954 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003955
3956out:
3957 mutex_unlock(&wl->mutex);
3958
3959 return ret;
3960}
3961
Eliad Peller37a41b42011-09-21 14:06:11 +03003962static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
3963 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003964{
3965
3966 struct wl1271 *wl = hw->priv;
3967 u64 mactime = ULLONG_MAX;
3968 int ret;
3969
3970 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3971
3972 mutex_lock(&wl->mutex);
3973
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003974 if (unlikely(wl->state == WL1271_STATE_OFF))
3975 goto out;
3976
Ido Yariva6208652011-03-01 15:14:41 +02003977 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003978 if (ret < 0)
3979 goto out;
3980
3981 ret = wl1271_acx_tsf_info(wl, &mactime);
3982 if (ret < 0)
3983 goto out_sleep;
3984
3985out_sleep:
3986 wl1271_ps_elp_sleep(wl);
3987
3988out:
3989 mutex_unlock(&wl->mutex);
3990 return mactime;
3991}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003992
John W. Linvilleece550d2010-07-28 16:41:06 -04003993static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3994 struct survey_info *survey)
3995{
3996 struct wl1271 *wl = hw->priv;
3997 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003998
John W. Linvilleece550d2010-07-28 16:41:06 -04003999 if (idx != 0)
4000 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004001
John W. Linvilleece550d2010-07-28 16:41:06 -04004002 survey->channel = conf->channel;
4003 survey->filled = SURVEY_INFO_NOISE_DBM;
4004 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004005
John W. Linvilleece550d2010-07-28 16:41:06 -04004006 return 0;
4007}
4008
Arik Nemtsov409622e2011-02-23 00:22:29 +02004009static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004010 struct wl12xx_vif *wlvif,
4011 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004012{
4013 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004014 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004015
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004016
4017 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004018 wl1271_warning("could not allocate HLID - too much stations");
4019 return -EBUSY;
4020 }
4021
4022 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004023 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4024 if (ret < 0) {
4025 wl1271_warning("could not allocate HLID - too many links");
4026 return -EBUSY;
4027 }
4028
4029 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004030 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004031 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004032 return 0;
4033}
4034
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004035void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004036{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004037 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004038 return;
4039
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004040 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004041 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004042 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004043 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004044 __clear_bit(hlid, &wl->ap_ps_map);
4045 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004046 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004047 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004048}
4049
4050static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4051 struct ieee80211_vif *vif,
4052 struct ieee80211_sta *sta)
4053{
4054 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004055 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004056 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004057 int ret = 0;
4058 u8 hlid;
4059
4060 mutex_lock(&wl->mutex);
4061
4062 if (unlikely(wl->state == WL1271_STATE_OFF))
4063 goto out;
4064
Eliad Peller536129c2011-10-05 11:55:45 +02004065 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004066 goto out;
4067
4068 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4069
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004070 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004071 if (ret < 0)
4072 goto out;
4073
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004074 wl_sta = (struct wl1271_station *)sta->drv_priv;
4075 hlid = wl_sta->hlid;
4076
Ido Yariva6208652011-03-01 15:14:41 +02004077 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004078 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004079 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004080
Eliad Peller1b92f152011-10-10 10:13:09 +02004081 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004082 if (ret < 0)
4083 goto out_sleep;
4084
Eliad Pellerb67476e2011-08-14 13:17:23 +03004085 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4086 if (ret < 0)
4087 goto out_sleep;
4088
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004089 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4090 if (ret < 0)
4091 goto out_sleep;
4092
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004093out_sleep:
4094 wl1271_ps_elp_sleep(wl);
4095
Arik Nemtsov409622e2011-02-23 00:22:29 +02004096out_free_sta:
4097 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004098 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004099
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004100out:
4101 mutex_unlock(&wl->mutex);
4102 return ret;
4103}
4104
4105static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4106 struct ieee80211_vif *vif,
4107 struct ieee80211_sta *sta)
4108{
4109 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004110 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004111 struct wl1271_station *wl_sta;
4112 int ret = 0, id;
4113
4114 mutex_lock(&wl->mutex);
4115
4116 if (unlikely(wl->state == WL1271_STATE_OFF))
4117 goto out;
4118
Eliad Peller536129c2011-10-05 11:55:45 +02004119 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004120 goto out;
4121
4122 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4123
4124 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004125 id = wl_sta->hlid;
4126 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004127 goto out;
4128
Ido Yariva6208652011-03-01 15:14:41 +02004129 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004130 if (ret < 0)
4131 goto out;
4132
Eliad Pellerc690ec82011-08-14 13:17:07 +03004133 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004134 if (ret < 0)
4135 goto out_sleep;
4136
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004137 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004138
4139out_sleep:
4140 wl1271_ps_elp_sleep(wl);
4141
4142out:
4143 mutex_unlock(&wl->mutex);
4144 return ret;
4145}
4146
Luciano Coelho4623ec72011-03-21 19:26:41 +02004147static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4148 struct ieee80211_vif *vif,
4149 enum ieee80211_ampdu_mlme_action action,
4150 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4151 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004152{
4153 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004154 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004155 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004156 u8 hlid, *ba_bitmap;
4157
4158 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4159 tid);
4160
4161 /* sanity check - the fields in FW are only 8bits wide */
4162 if (WARN_ON(tid > 0xFF))
4163 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004164
4165 mutex_lock(&wl->mutex);
4166
4167 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4168 ret = -EAGAIN;
4169 goto out;
4170 }
4171
Eliad Peller536129c2011-10-05 11:55:45 +02004172 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004173 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004174 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004175 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004176 struct wl1271_station *wl_sta;
4177
4178 wl_sta = (struct wl1271_station *)sta->drv_priv;
4179 hlid = wl_sta->hlid;
4180 ba_bitmap = &wl->links[hlid].ba_bitmap;
4181 } else {
4182 ret = -EINVAL;
4183 goto out;
4184 }
4185
Ido Yariva6208652011-03-01 15:14:41 +02004186 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004187 if (ret < 0)
4188 goto out;
4189
Shahar Levi70559a02011-05-22 16:10:22 +03004190 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4191 tid, action);
4192
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004193 switch (action) {
4194 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004195 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004196 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004197 break;
4198 }
4199
4200 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4201 ret = -EBUSY;
4202 wl1271_error("exceeded max RX BA sessions");
4203 break;
4204 }
4205
4206 if (*ba_bitmap & BIT(tid)) {
4207 ret = -EINVAL;
4208 wl1271_error("cannot enable RX BA session on active "
4209 "tid: %d", tid);
4210 break;
4211 }
4212
4213 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4214 hlid);
4215 if (!ret) {
4216 *ba_bitmap |= BIT(tid);
4217 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004218 }
4219 break;
4220
4221 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004222 if (!(*ba_bitmap & BIT(tid))) {
4223 ret = -EINVAL;
4224 wl1271_error("no active RX BA session on tid: %d",
4225 tid);
4226 break;
4227 }
4228
4229 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4230 hlid);
4231 if (!ret) {
4232 *ba_bitmap &= ~BIT(tid);
4233 wl->ba_rx_session_count--;
4234 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004235 break;
4236
4237 /*
4238 * The BA initiator session management in FW independently.
4239 * Falling break here on purpose for all TX APDU commands.
4240 */
4241 case IEEE80211_AMPDU_TX_START:
4242 case IEEE80211_AMPDU_TX_STOP:
4243 case IEEE80211_AMPDU_TX_OPERATIONAL:
4244 ret = -EINVAL;
4245 break;
4246
4247 default:
4248 wl1271_error("Incorrect ampdu action id=%x\n", action);
4249 ret = -EINVAL;
4250 }
4251
4252 wl1271_ps_elp_sleep(wl);
4253
4254out:
4255 mutex_unlock(&wl->mutex);
4256
4257 return ret;
4258}
4259
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004260static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4261 struct ieee80211_vif *vif,
4262 const struct cfg80211_bitrate_mask *mask)
4263{
Eliad Peller83587502011-10-10 10:12:53 +02004264 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004265 struct wl1271 *wl = hw->priv;
4266 int i;
4267
4268 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4269 mask->control[NL80211_BAND_2GHZ].legacy,
4270 mask->control[NL80211_BAND_5GHZ].legacy);
4271
4272 mutex_lock(&wl->mutex);
4273
4274 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004275 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004276 wl1271_tx_enabled_rates_get(wl,
4277 mask->control[i].legacy,
4278 i);
4279 mutex_unlock(&wl->mutex);
4280
4281 return 0;
4282}
4283
Shahar Levi6d158ff2011-09-08 13:01:33 +03004284static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4285 struct ieee80211_channel_switch *ch_switch)
4286{
4287 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004288 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004289 int ret;
4290
4291 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4292
4293 mutex_lock(&wl->mutex);
4294
4295 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4296 mutex_unlock(&wl->mutex);
4297 ieee80211_chswitch_done(wl->vif, false);
4298 return;
4299 }
4300
4301 ret = wl1271_ps_elp_wakeup(wl);
4302 if (ret < 0)
4303 goto out;
4304
Eliad Peller52630c52011-10-10 10:13:08 +02004305 /* TODO: change mac80211 to pass vif as param */
4306 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4307 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004308
Eliad Peller52630c52011-10-10 10:13:08 +02004309 if (!ret)
4310 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4311 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004312
4313 wl1271_ps_elp_sleep(wl);
4314
4315out:
4316 mutex_unlock(&wl->mutex);
4317}
4318
Arik Nemtsov33437892011-04-26 23:35:39 +03004319static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4320{
4321 struct wl1271 *wl = hw->priv;
4322 bool ret = false;
4323
4324 mutex_lock(&wl->mutex);
4325
4326 if (unlikely(wl->state == WL1271_STATE_OFF))
4327 goto out;
4328
4329 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004330 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004331out:
4332 mutex_unlock(&wl->mutex);
4333
4334 return ret;
4335}
4336
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004337/* can't be const, mac80211 writes to this */
4338static struct ieee80211_rate wl1271_rates[] = {
4339 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004340 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4341 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004342 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004343 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4344 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004345 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4346 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004347 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4348 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004349 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4350 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004351 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4352 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004353 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4354 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004355 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4356 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004357 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004358 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4359 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004360 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004361 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4362 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004363 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004364 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4365 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004366 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004367 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4368 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004369 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004370 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4371 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004372 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004373 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4374 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004375 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004376 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4377 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004378};
4379
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004380/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004381static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004382 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004383 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004384 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4385 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4386 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004387 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004388 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4389 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4390 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004391 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004392 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4393 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4394 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004395 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004396};
4397
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004398/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004399static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004400 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004401 7, /* CONF_HW_RXTX_RATE_MCS7 */
4402 6, /* CONF_HW_RXTX_RATE_MCS6 */
4403 5, /* CONF_HW_RXTX_RATE_MCS5 */
4404 4, /* CONF_HW_RXTX_RATE_MCS4 */
4405 3, /* CONF_HW_RXTX_RATE_MCS3 */
4406 2, /* CONF_HW_RXTX_RATE_MCS2 */
4407 1, /* CONF_HW_RXTX_RATE_MCS1 */
4408 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004409
4410 11, /* CONF_HW_RXTX_RATE_54 */
4411 10, /* CONF_HW_RXTX_RATE_48 */
4412 9, /* CONF_HW_RXTX_RATE_36 */
4413 8, /* CONF_HW_RXTX_RATE_24 */
4414
4415 /* TI-specific rate */
4416 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4417
4418 7, /* CONF_HW_RXTX_RATE_18 */
4419 6, /* CONF_HW_RXTX_RATE_12 */
4420 3, /* CONF_HW_RXTX_RATE_11 */
4421 5, /* CONF_HW_RXTX_RATE_9 */
4422 4, /* CONF_HW_RXTX_RATE_6 */
4423 2, /* CONF_HW_RXTX_RATE_5_5 */
4424 1, /* CONF_HW_RXTX_RATE_2 */
4425 0 /* CONF_HW_RXTX_RATE_1 */
4426};
4427
Shahar Levie8b03a22010-10-13 16:09:39 +02004428/* 11n STA capabilities */
4429#define HW_RX_HIGHEST_RATE 72
4430
Shahar Levi00d20102010-11-08 11:20:10 +00004431#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004432 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4433 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004434 .ht_supported = true, \
4435 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4436 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4437 .mcs = { \
4438 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4439 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4440 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4441 }, \
4442}
4443
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004444/* can't be const, mac80211 writes to this */
4445static struct ieee80211_supported_band wl1271_band_2ghz = {
4446 .channels = wl1271_channels,
4447 .n_channels = ARRAY_SIZE(wl1271_channels),
4448 .bitrates = wl1271_rates,
4449 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004450 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004451};
4452
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004453/* 5 GHz data rates for WL1273 */
4454static struct ieee80211_rate wl1271_rates_5ghz[] = {
4455 { .bitrate = 60,
4456 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4457 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4458 { .bitrate = 90,
4459 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4460 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4461 { .bitrate = 120,
4462 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4463 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4464 { .bitrate = 180,
4465 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4466 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4467 { .bitrate = 240,
4468 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4469 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4470 { .bitrate = 360,
4471 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4472 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4473 { .bitrate = 480,
4474 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4475 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4476 { .bitrate = 540,
4477 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4478 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4479};
4480
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004481/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004482static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004483 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4484 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4485 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4486 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4487 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4488 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4489 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4490 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4491 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4492 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4493 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4494 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4495 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4496 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4497 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4498 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4499 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4500 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4501 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4502 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4503 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4504 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4505 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4506 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4507 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4508 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4509 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4510 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4511 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4512 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4513 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4514 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4515 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4516 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004517};
4518
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004519/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004520static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004521 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004522 7, /* CONF_HW_RXTX_RATE_MCS7 */
4523 6, /* CONF_HW_RXTX_RATE_MCS6 */
4524 5, /* CONF_HW_RXTX_RATE_MCS5 */
4525 4, /* CONF_HW_RXTX_RATE_MCS4 */
4526 3, /* CONF_HW_RXTX_RATE_MCS3 */
4527 2, /* CONF_HW_RXTX_RATE_MCS2 */
4528 1, /* CONF_HW_RXTX_RATE_MCS1 */
4529 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004530
4531 7, /* CONF_HW_RXTX_RATE_54 */
4532 6, /* CONF_HW_RXTX_RATE_48 */
4533 5, /* CONF_HW_RXTX_RATE_36 */
4534 4, /* CONF_HW_RXTX_RATE_24 */
4535
4536 /* TI-specific rate */
4537 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4538
4539 3, /* CONF_HW_RXTX_RATE_18 */
4540 2, /* CONF_HW_RXTX_RATE_12 */
4541 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4542 1, /* CONF_HW_RXTX_RATE_9 */
4543 0, /* CONF_HW_RXTX_RATE_6 */
4544 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4545 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4546 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4547};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004548
4549static struct ieee80211_supported_band wl1271_band_5ghz = {
4550 .channels = wl1271_channels_5ghz,
4551 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4552 .bitrates = wl1271_rates_5ghz,
4553 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004554 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004555};
4556
Tobias Klausera0ea9492010-05-20 10:38:11 +02004557static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004558 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4559 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4560};
4561
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004562static const struct ieee80211_ops wl1271_ops = {
4563 .start = wl1271_op_start,
4564 .stop = wl1271_op_stop,
4565 .add_interface = wl1271_op_add_interface,
4566 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004567#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004568 .suspend = wl1271_op_suspend,
4569 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004570#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004571 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004572 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004573 .configure_filter = wl1271_op_configure_filter,
4574 .tx = wl1271_op_tx,
4575 .set_key = wl1271_op_set_key,
4576 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004577 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004578 .sched_scan_start = wl1271_op_sched_scan_start,
4579 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004580 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004581 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004582 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004583 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004584 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004585 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004586 .sta_add = wl1271_op_sta_add,
4587 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004588 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004589 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004590 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004591 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004592 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004593};
4594
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004595
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004596u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004597{
4598 u8 idx;
4599
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004600 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004601
4602 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4603 wl1271_error("Illegal RX rate from HW: %d", rate);
4604 return 0;
4605 }
4606
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004607 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004608 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4609 wl1271_error("Unsupported RX rate from HW: %d", rate);
4610 return 0;
4611 }
4612
4613 return idx;
4614}
4615
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004616static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4617 struct device_attribute *attr,
4618 char *buf)
4619{
4620 struct wl1271 *wl = dev_get_drvdata(dev);
4621 ssize_t len;
4622
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004623 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004624
4625 mutex_lock(&wl->mutex);
4626 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4627 wl->sg_enabled);
4628 mutex_unlock(&wl->mutex);
4629
4630 return len;
4631
4632}
4633
4634static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4635 struct device_attribute *attr,
4636 const char *buf, size_t count)
4637{
4638 struct wl1271 *wl = dev_get_drvdata(dev);
4639 unsigned long res;
4640 int ret;
4641
Luciano Coelho6277ed62011-04-01 17:49:54 +03004642 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004643 if (ret < 0) {
4644 wl1271_warning("incorrect value written to bt_coex_mode");
4645 return count;
4646 }
4647
4648 mutex_lock(&wl->mutex);
4649
4650 res = !!res;
4651
4652 if (res == wl->sg_enabled)
4653 goto out;
4654
4655 wl->sg_enabled = res;
4656
4657 if (wl->state == WL1271_STATE_OFF)
4658 goto out;
4659
Ido Yariva6208652011-03-01 15:14:41 +02004660 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004661 if (ret < 0)
4662 goto out;
4663
4664 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4665 wl1271_ps_elp_sleep(wl);
4666
4667 out:
4668 mutex_unlock(&wl->mutex);
4669 return count;
4670}
4671
4672static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4673 wl1271_sysfs_show_bt_coex_state,
4674 wl1271_sysfs_store_bt_coex_state);
4675
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004676static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4677 struct device_attribute *attr,
4678 char *buf)
4679{
4680 struct wl1271 *wl = dev_get_drvdata(dev);
4681 ssize_t len;
4682
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004683 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004684
4685 mutex_lock(&wl->mutex);
4686 if (wl->hw_pg_ver >= 0)
4687 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4688 else
4689 len = snprintf(buf, len, "n/a\n");
4690 mutex_unlock(&wl->mutex);
4691
4692 return len;
4693}
4694
Gery Kahn6f07b722011-07-18 14:21:49 +03004695static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004696 wl1271_sysfs_show_hw_pg_ver, NULL);
4697
Ido Yariv95dac04f2011-06-06 14:57:06 +03004698static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4699 struct bin_attribute *bin_attr,
4700 char *buffer, loff_t pos, size_t count)
4701{
4702 struct device *dev = container_of(kobj, struct device, kobj);
4703 struct wl1271 *wl = dev_get_drvdata(dev);
4704 ssize_t len;
4705 int ret;
4706
4707 ret = mutex_lock_interruptible(&wl->mutex);
4708 if (ret < 0)
4709 return -ERESTARTSYS;
4710
4711 /* Let only one thread read the log at a time, blocking others */
4712 while (wl->fwlog_size == 0) {
4713 DEFINE_WAIT(wait);
4714
4715 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4716 &wait,
4717 TASK_INTERRUPTIBLE);
4718
4719 if (wl->fwlog_size != 0) {
4720 finish_wait(&wl->fwlog_waitq, &wait);
4721 break;
4722 }
4723
4724 mutex_unlock(&wl->mutex);
4725
4726 schedule();
4727 finish_wait(&wl->fwlog_waitq, &wait);
4728
4729 if (signal_pending(current))
4730 return -ERESTARTSYS;
4731
4732 ret = mutex_lock_interruptible(&wl->mutex);
4733 if (ret < 0)
4734 return -ERESTARTSYS;
4735 }
4736
4737 /* Check if the fwlog is still valid */
4738 if (wl->fwlog_size < 0) {
4739 mutex_unlock(&wl->mutex);
4740 return 0;
4741 }
4742
4743 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4744 len = min(count, (size_t)wl->fwlog_size);
4745 wl->fwlog_size -= len;
4746 memcpy(buffer, wl->fwlog, len);
4747
4748 /* Make room for new messages */
4749 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4750
4751 mutex_unlock(&wl->mutex);
4752
4753 return len;
4754}
4755
4756static struct bin_attribute fwlog_attr = {
4757 .attr = {.name = "fwlog", .mode = S_IRUSR},
4758 .read = wl1271_sysfs_read_fwlog,
4759};
4760
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004761int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004762{
4763 int ret;
4764
4765 if (wl->mac80211_registered)
4766 return 0;
4767
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004768 ret = wl1271_fetch_nvs(wl);
4769 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004770 /* NOTE: The wl->nvs->nvs element must be first, in
4771 * order to simplify the casting, we assume it is at
4772 * the beginning of the wl->nvs structure.
4773 */
4774 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004775
4776 wl->mac_addr[0] = nvs_ptr[11];
4777 wl->mac_addr[1] = nvs_ptr[10];
4778 wl->mac_addr[2] = nvs_ptr[6];
4779 wl->mac_addr[3] = nvs_ptr[5];
4780 wl->mac_addr[4] = nvs_ptr[4];
4781 wl->mac_addr[5] = nvs_ptr[3];
4782 }
4783
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004784 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4785
4786 ret = ieee80211_register_hw(wl->hw);
4787 if (ret < 0) {
4788 wl1271_error("unable to register mac80211 hw: %d", ret);
4789 return ret;
4790 }
4791
4792 wl->mac80211_registered = true;
4793
Eliad Pellerd60080a2010-11-24 12:53:16 +02004794 wl1271_debugfs_init(wl);
4795
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004796 register_netdevice_notifier(&wl1271_dev_notifier);
4797
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004798 wl1271_notice("loaded");
4799
4800 return 0;
4801}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004802EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004803
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004804void wl1271_unregister_hw(struct wl1271 *wl)
4805{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004806 if (wl->state == WL1271_STATE_PLT)
4807 __wl1271_plt_stop(wl);
4808
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004809 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004810 ieee80211_unregister_hw(wl->hw);
4811 wl->mac80211_registered = false;
4812
4813}
4814EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4815
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004816int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004817{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004818 static const u32 cipher_suites[] = {
4819 WLAN_CIPHER_SUITE_WEP40,
4820 WLAN_CIPHER_SUITE_WEP104,
4821 WLAN_CIPHER_SUITE_TKIP,
4822 WLAN_CIPHER_SUITE_CCMP,
4823 WL1271_CIPHER_SUITE_GEM,
4824 };
4825
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004826 /* The tx descriptor buffer and the TKIP space. */
4827 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4828 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004829
4830 /* unit us */
4831 /* FIXME: find a proper value */
4832 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004833 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004834
4835 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004836 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004837 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004838 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004839 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004840 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004841 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004842 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004843 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004844 IEEE80211_HW_AP_LINK_PS |
4845 IEEE80211_HW_AMPDU_AGGREGATION |
4846 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004847
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004848 wl->hw->wiphy->cipher_suites = cipher_suites;
4849 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4850
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004851 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004852 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4853 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004854 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004855 wl->hw->wiphy->max_sched_scan_ssids = 16;
4856 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004857 /*
4858 * Maximum length of elements in scanning probe request templates
4859 * should be the maximum length possible for a template, without
4860 * the IEEE80211 header of the template
4861 */
Eliad Peller154037d2011-08-14 13:17:12 +03004862 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004863 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004864
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004865 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4866 sizeof(struct ieee80211_header);
4867
Eliad Peller1ec23f72011-08-25 14:26:54 +03004868 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4869
Luciano Coelho4a31c112011-03-21 23:16:14 +02004870 /* make sure all our channels fit in the scanned_ch bitmask */
4871 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4872 ARRAY_SIZE(wl1271_channels_5ghz) >
4873 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004874 /*
4875 * We keep local copies of the band structs because we need to
4876 * modify them on a per-device basis.
4877 */
4878 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4879 sizeof(wl1271_band_2ghz));
4880 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4881 sizeof(wl1271_band_5ghz));
4882
4883 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4884 &wl->bands[IEEE80211_BAND_2GHZ];
4885 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4886 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004887
Kalle Valo12bd8942010-03-18 12:26:33 +02004888 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004889 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004890
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004891 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4892
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004893 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004894
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004895 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004896 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004897
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004898 wl->hw->max_rx_aggregation_subframes = 8;
4899
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004900 return 0;
4901}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004902EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004903
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004904#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004905
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004906struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004907{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004908 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004909 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004910 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004911 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004912 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004913
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004914 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004915
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004916 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4917 if (!hw) {
4918 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004919 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004920 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004921 }
4922
Julia Lawall929ebd32010-05-15 23:16:39 +02004923 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004924 if (!plat_dev) {
4925 wl1271_error("could not allocate platform_device");
4926 ret = -ENOMEM;
4927 goto err_plat_alloc;
4928 }
4929
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004930 wl = hw->priv;
4931 memset(wl, 0, sizeof(*wl));
4932
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004933 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02004934 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004935
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004936 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004937 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004938
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004939 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004940 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004941 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4942
Ido Yariva6208652011-03-01 15:14:41 +02004943 skb_queue_head_init(&wl->deferred_rx_queue);
4944 skb_queue_head_init(&wl->deferred_tx_queue);
4945
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004946 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02004947 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004948 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4949 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4950 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004951
Eliad Peller92ef8962011-06-07 12:50:46 +03004952 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4953 if (!wl->freezable_wq) {
4954 ret = -ENOMEM;
4955 goto err_hw;
4956 }
4957
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004958 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004959 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004960 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004961 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004962 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004963 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004964 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004965 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004966 wl->ap_ps_map = 0;
4967 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004968 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004969 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004970 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03004971 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004972 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03004973 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03004974 wl->fwlog_size = 0;
4975 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004976
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004977 /* The system link is always allocated */
4978 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4979
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004980 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004981 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004982 wl->tx_frames[i] = NULL;
4983
4984 spin_lock_init(&wl->wl_lock);
4985
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004986 wl->state = WL1271_STATE_OFF;
4987 mutex_init(&wl->mutex);
4988
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004989 /* Apply default driver configuration. */
4990 wl1271_conf_init(wl);
4991
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004992 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4993 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4994 if (!wl->aggr_buf) {
4995 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004996 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004997 }
4998
Ido Yariv990f5de2011-03-31 10:06:59 +02004999 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5000 if (!wl->dummy_packet) {
5001 ret = -ENOMEM;
5002 goto err_aggr;
5003 }
5004
Ido Yariv95dac04f2011-06-06 14:57:06 +03005005 /* Allocate one page for the FW log */
5006 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5007 if (!wl->fwlog) {
5008 ret = -ENOMEM;
5009 goto err_dummy_packet;
5010 }
5011
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005012 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005013 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005014 if (ret) {
5015 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03005016 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005017 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005018 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005019
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005020 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005021 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005022 if (ret < 0) {
5023 wl1271_error("failed to create sysfs file bt_coex_state");
5024 goto err_platform;
5025 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005026
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005027 /* Create sysfs file to get HW PG version */
5028 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5029 if (ret < 0) {
5030 wl1271_error("failed to create sysfs file hw_pg_ver");
5031 goto err_bt_coex_state;
5032 }
5033
Ido Yariv95dac04f2011-06-06 14:57:06 +03005034 /* Create sysfs file for the FW log */
5035 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
5036 if (ret < 0) {
5037 wl1271_error("failed to create sysfs file fwlog");
5038 goto err_hw_pg_ver;
5039 }
5040
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005041 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005042
Ido Yariv95dac04f2011-06-06 14:57:06 +03005043err_hw_pg_ver:
5044 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5045
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005046err_bt_coex_state:
5047 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
5048
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005049err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005050 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005051
Ido Yariv95dac04f2011-06-06 14:57:06 +03005052err_fwlog:
5053 free_page((unsigned long)wl->fwlog);
5054
Ido Yariv990f5de2011-03-31 10:06:59 +02005055err_dummy_packet:
5056 dev_kfree_skb(wl->dummy_packet);
5057
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005058err_aggr:
5059 free_pages((unsigned long)wl->aggr_buf, order);
5060
Eliad Peller92ef8962011-06-07 12:50:46 +03005061err_wq:
5062 destroy_workqueue(wl->freezable_wq);
5063
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005064err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005065 wl1271_debugfs_exit(wl);
5066 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005067
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005068err_plat_alloc:
5069 ieee80211_free_hw(hw);
5070
5071err_hw_alloc:
5072
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005073 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005074}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005075EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005076
5077int wl1271_free_hw(struct wl1271 *wl)
5078{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005079 /* Unblock any fwlog readers */
5080 mutex_lock(&wl->mutex);
5081 wl->fwlog_size = -1;
5082 wake_up_interruptible_all(&wl->fwlog_waitq);
5083 mutex_unlock(&wl->mutex);
5084
5085 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005086
5087 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5088
5089 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005090 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005091 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005092 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005093 free_pages((unsigned long)wl->aggr_buf,
5094 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005095 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005096
5097 wl1271_debugfs_exit(wl);
5098
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005099 vfree(wl->fw);
5100 wl->fw = NULL;
5101 kfree(wl->nvs);
5102 wl->nvs = NULL;
5103
5104 kfree(wl->fw_status);
5105 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005106 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005107
5108 ieee80211_free_hw(wl->hw);
5109
5110 return 0;
5111}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005112EXPORT_SYMBOL_GPL(wl1271_free_hw);
5113
Guy Eilam491bbd62011-01-12 10:33:29 +01005114u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005115EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005116module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005117MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5118
Ido Yariv95dac04f2011-06-06 14:57:06 +03005119module_param_named(fwlog, fwlog_param, charp, 0);
5120MODULE_PARM_DESC(keymap,
5121 "FW logger options: continuous, ondemand, dbgpins or disable");
5122
Eliad Peller2a5bff02011-08-25 18:10:59 +03005123module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5124MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5125
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005126MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005127MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005128MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");