blob: 8863ea542ea6a9352fdcbfd56256c5d43d208c78 [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-Cohen958b20e02011-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,
380 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200381static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200382
383
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200384static void wl1271_device_release(struct device *dev)
385{
386
387}
388
389static struct platform_device wl1271_device = {
390 .name = "wl1271",
391 .id = -1,
392
393 /* device model insists to have a release function */
394 .dev = {
395 .release = wl1271_device_release,
396 },
397};
398
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200399static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300400static LIST_HEAD(wl_list);
401
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300402static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
403{
404 int ret;
405 if (operstate != IF_OPER_UP)
406 return 0;
407
408 if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
409 return 0;
410
Eliad Pellerb67476e2011-08-14 13:17:23 +0300411 ret = wl12xx_cmd_set_peer_state(wl, wl->sta_hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300412 if (ret < 0)
413 return ret;
414
Eliad Peller251c1772011-08-14 13:17:17 +0300415 wl12xx_croc(wl, wl->role_id);
416
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300417 wl1271_info("Association completed.");
418 return 0;
419}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300420static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
421 void *arg)
422{
423 struct net_device *dev = arg;
424 struct wireless_dev *wdev;
425 struct wiphy *wiphy;
426 struct ieee80211_hw *hw;
427 struct wl1271 *wl;
428 struct wl1271 *wl_temp;
429 int ret = 0;
430
431 /* Check that this notification is for us. */
432 if (what != NETDEV_CHANGE)
433 return NOTIFY_DONE;
434
435 wdev = dev->ieee80211_ptr;
436 if (wdev == NULL)
437 return NOTIFY_DONE;
438
439 wiphy = wdev->wiphy;
440 if (wiphy == NULL)
441 return NOTIFY_DONE;
442
443 hw = wiphy_priv(wiphy);
444 if (hw == NULL)
445 return NOTIFY_DONE;
446
447 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200448 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300449 list_for_each_entry(wl, &wl_list, list) {
450 if (wl == wl_temp)
451 break;
452 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200453 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300454 if (wl != wl_temp)
455 return NOTIFY_DONE;
456
457 mutex_lock(&wl->mutex);
458
459 if (wl->state == WL1271_STATE_OFF)
460 goto out;
461
462 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
463 goto out;
464
Ido Yariva6208652011-03-01 15:14:41 +0200465 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300466 if (ret < 0)
467 goto out;
468
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300469 wl1271_check_operstate(wl, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300470
471 wl1271_ps_elp_sleep(wl);
472
473out:
474 mutex_unlock(&wl->mutex);
475
476 return NOTIFY_OK;
477}
478
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100479static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200480 struct regulatory_request *request)
481{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100482 struct ieee80211_supported_band *band;
483 struct ieee80211_channel *ch;
484 int i;
485
486 band = wiphy->bands[IEEE80211_BAND_5GHZ];
487 for (i = 0; i < band->n_channels; i++) {
488 ch = &band->channels[i];
489 if (ch->flags & IEEE80211_CHAN_DISABLED)
490 continue;
491
492 if (ch->flags & IEEE80211_CHAN_RADAR)
493 ch->flags |= IEEE80211_CHAN_NO_IBSS |
494 IEEE80211_CHAN_PASSIVE_SCAN;
495
496 }
497
498 return 0;
499}
500
Eliad Peller77ddaa12011-05-15 11:10:29 +0300501static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
502{
503 int ret = 0;
504
505 /* we should hold wl->mutex */
506 ret = wl1271_acx_ps_rx_streaming(wl, enable);
507 if (ret < 0)
508 goto out;
509
510 if (enable)
511 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
512 else
513 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
514out:
515 return ret;
516}
517
518/*
519 * this function is being called when the rx_streaming interval
520 * has beed changed or rx_streaming should be disabled
521 */
522int wl1271_recalc_rx_streaming(struct wl1271 *wl)
523{
524 int ret = 0;
525 int period = wl->conf.rx_streaming.interval;
526
527 /* don't reconfigure if rx_streaming is disabled */
528 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
529 goto out;
530
531 /* reconfigure/disable according to new streaming_period */
532 if (period &&
533 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
534 (wl->conf.rx_streaming.always ||
535 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
536 ret = wl1271_set_rx_streaming(wl, true);
537 else {
538 ret = wl1271_set_rx_streaming(wl, false);
539 /* don't cancel_work_sync since we might deadlock */
540 del_timer_sync(&wl->rx_streaming_timer);
541 }
542out:
543 return ret;
544}
545
546static void wl1271_rx_streaming_enable_work(struct work_struct *work)
547{
548 int ret;
549 struct wl1271 *wl =
550 container_of(work, struct wl1271, rx_streaming_enable_work);
551
552 mutex_lock(&wl->mutex);
553
554 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
555 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
556 (!wl->conf.rx_streaming.always &&
557 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
558 goto out;
559
560 if (!wl->conf.rx_streaming.interval)
561 goto out;
562
563 ret = wl1271_ps_elp_wakeup(wl);
564 if (ret < 0)
565 goto out;
566
567 ret = wl1271_set_rx_streaming(wl, true);
568 if (ret < 0)
569 goto out_sleep;
570
571 /* stop it after some time of inactivity */
572 mod_timer(&wl->rx_streaming_timer,
573 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
574
575out_sleep:
576 wl1271_ps_elp_sleep(wl);
577out:
578 mutex_unlock(&wl->mutex);
579}
580
581static void wl1271_rx_streaming_disable_work(struct work_struct *work)
582{
583 int ret;
584 struct wl1271 *wl =
585 container_of(work, struct wl1271, rx_streaming_disable_work);
586
587 mutex_lock(&wl->mutex);
588
589 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
590 goto out;
591
592 ret = wl1271_ps_elp_wakeup(wl);
593 if (ret < 0)
594 goto out;
595
596 ret = wl1271_set_rx_streaming(wl, false);
597 if (ret)
598 goto out_sleep;
599
600out_sleep:
601 wl1271_ps_elp_sleep(wl);
602out:
603 mutex_unlock(&wl->mutex);
604}
605
606static void wl1271_rx_streaming_timer(unsigned long data)
607{
608 struct wl1271 *wl = (struct wl1271 *)data;
609 ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
610}
611
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300612static void wl1271_conf_init(struct wl1271 *wl)
613{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300614
615 /*
616 * This function applies the default configuration to the driver. This
617 * function is invoked upon driver load (spi probe.)
618 *
619 * The configuration is stored in a run-time structure in order to
620 * facilitate for run-time adjustment of any of the parameters. Making
621 * changes to the configuration structure will apply the new values on
622 * the next interface up (wl1271_op_start.)
623 */
624
625 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300626 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300627
Ido Yariv95dac04f2011-06-06 14:57:06 +0300628 /* Adjust settings according to optional module parameters */
629 if (fwlog_param) {
630 if (!strcmp(fwlog_param, "continuous")) {
631 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
632 } else if (!strcmp(fwlog_param, "ondemand")) {
633 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
634 } else if (!strcmp(fwlog_param, "dbgpins")) {
635 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
636 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
637 } else if (!strcmp(fwlog_param, "disable")) {
638 wl->conf.fwlog.mem_blocks = 0;
639 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
640 } else {
641 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
642 }
643 }
644}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300645
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300646static int wl1271_plt_init(struct wl1271 *wl)
647{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200648 struct conf_tx_ac_category *conf_ac;
649 struct conf_tx_tid *conf_tid;
650 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651
Shahar Levi49d750ca2011-03-06 16:32:09 +0200652 if (wl->chip.id == CHIP_ID_1283_PG20)
653 ret = wl128x_cmd_general_parms(wl);
654 else
655 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200656 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200657 return ret;
658
Shahar Levi49d750ca2011-03-06 16:32:09 +0200659 if (wl->chip.id == CHIP_ID_1283_PG20)
660 ret = wl128x_cmd_radio_parms(wl);
661 else
662 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200663 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200664 return ret;
665
Shahar Levi49d750ca2011-03-06 16:32:09 +0200666 if (wl->chip.id != CHIP_ID_1283_PG20) {
667 ret = wl1271_cmd_ext_radio_parms(wl);
668 if (ret < 0)
669 return ret;
670 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200671 if (ret < 0)
672 return ret;
673
Shahar Levi48a61472011-03-06 16:32:08 +0200674 /* Chip-specific initializations */
675 ret = wl1271_chip_specific_init(wl);
676 if (ret < 0)
677 return ret;
678
Eliad Peller92c77c72011-10-05 11:55:40 +0200679 ret = wl1271_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200680 if (ret < 0)
681 return ret;
682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 ret = wl1271_acx_init_mem_config(wl);
684 if (ret < 0)
685 return ret;
686
Luciano Coelho12419cc2010-02-18 13:25:44 +0200687 /* PHY layer config */
688 ret = wl1271_init_phy_config(wl);
689 if (ret < 0)
690 goto out_free_memmap;
691
692 ret = wl1271_acx_dco_itrim_params(wl);
693 if (ret < 0)
694 goto out_free_memmap;
695
696 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200697 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200698 if (ret < 0)
699 goto out_free_memmap;
700
701 /* Bluetooth WLAN coexistence */
702 ret = wl1271_init_pta(wl);
703 if (ret < 0)
704 goto out_free_memmap;
705
Shahar Leviff868432011-04-11 15:41:46 +0300706 /* FM WLAN coexistence */
707 ret = wl1271_acx_fm_coex(wl);
708 if (ret < 0)
709 goto out_free_memmap;
710
Luciano Coelho12419cc2010-02-18 13:25:44 +0200711 /* Energy detection */
712 ret = wl1271_init_energy_detection(wl);
713 if (ret < 0)
714 goto out_free_memmap;
715
Eliad Peller7f0979882011-08-14 13:17:06 +0300716 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600717 if (ret < 0)
718 goto out_free_memmap;
719
Luciano Coelho12419cc2010-02-18 13:25:44 +0200720 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100721 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200722 if (ret < 0)
723 goto out_free_memmap;
724
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200725 /* Default TID/AC configuration */
726 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200727 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200728 conf_ac = &wl->conf.tx.ac_conf[i];
729 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
730 conf_ac->cw_max, conf_ac->aifsn,
731 conf_ac->tx_op_limit);
732 if (ret < 0)
733 goto out_free_memmap;
734
Luciano Coelho12419cc2010-02-18 13:25:44 +0200735 conf_tid = &wl->conf.tx.tid_conf[i];
736 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
737 conf_tid->channel_type,
738 conf_tid->tsid,
739 conf_tid->ps_scheme,
740 conf_tid->ack_policy,
741 conf_tid->apsd_conf[0],
742 conf_tid->apsd_conf[1]);
743 if (ret < 0)
744 goto out_free_memmap;
745 }
746
Luciano Coelho12419cc2010-02-18 13:25:44 +0200747 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200748 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300749 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200750 goto out_free_memmap;
751
752 /* Configure for CAM power saving (ie. always active) */
753 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
754 if (ret < 0)
755 goto out_free_memmap;
756
757 /* configure PM */
758 ret = wl1271_acx_pm_config(wl);
759 if (ret < 0)
760 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300761
762 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200763
764 out_free_memmap:
765 kfree(wl->target_mem_map);
766 wl->target_mem_map = NULL;
767
768 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300769}
770
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300771static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200772{
Arik Nemtsovda032092011-08-25 12:43:15 +0300773 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200774
775 /* only regulate station links */
776 if (hlid < WL1271_AP_STA_HLID_START)
777 return;
778
779 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300780 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200781
782 /*
783 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300784 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200785 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300786 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200787 wl1271_ps_link_end(wl, hlid);
788
Arik Nemtsovda032092011-08-25 12:43:15 +0300789 /*
790 * Start high-level PS if the STA is asleep with enough blocks in FW.
791 * Make an exception if this is the only connected station. In this
792 * case FW-memory congestion is not a problem.
793 */
794 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200795 wl1271_ps_link_start(wl, hlid, true);
796}
797
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300798bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
799{
Arik Nemtsov04216da2011-08-14 13:17:38 +0300800 int id;
801
802 /* global/broadcast "stations" are always active */
803 if (hlid < WL1271_AP_STA_HLID_START)
804 return true;
805
806 id = hlid - WL1271_AP_STA_HLID_START;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300807 return test_bit(id, wl->ap_hlid_map);
808}
809
810static void wl12xx_irq_update_links_status(struct wl1271 *wl,
811 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200812{
813 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300814 u8 hlid, cnt;
815
816 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200817
818 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
819 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
820 wl1271_debug(DEBUG_PSM,
821 "link ps prev 0x%x cur 0x%x changed 0x%x",
822 wl->ap_fw_ps_map, cur_fw_ps_map,
823 wl->ap_fw_ps_map ^ cur_fw_ps_map);
824
825 wl->ap_fw_ps_map = cur_fw_ps_map;
826 }
827
828 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300829 if (!wl1271_is_active_sta(wl, hlid))
830 continue;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200831
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300832 cnt = status->tx_lnk_free_pkts[hlid] -
833 wl->links[hlid].prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200834
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300835 wl->links[hlid].prev_freed_pkts =
836 status->tx_lnk_free_pkts[hlid];
837 wl->links[hlid].allocated_pkts -= cnt;
838
839 wl12xx_irq_ps_regulate_link(wl, hlid,
840 wl->links[hlid].allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200841 }
842}
843
Eliad Peller4d56ad92011-08-14 13:17:05 +0300844static void wl12xx_fw_status(struct wl1271 *wl,
845 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200847 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200848 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300849 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300850 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300851
Eliad Peller4d56ad92011-08-14 13:17:05 +0300852 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200853
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300854 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
855 "drv_rx_counter = %d, tx_results_counter = %d)",
856 status->intr,
857 status->fw_rx_counter,
858 status->drv_rx_counter,
859 status->tx_results_counter);
860
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300861 for (i = 0; i < NUM_TX_QUEUES; i++) {
862 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300863 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300864 (status->tx_released_pkts[i] -
865 wl->tx_pkts_freed[i]) & 0xff;
866
867 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
868 }
869
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300870 /* prevent wrap-around in total blocks counter */
871 if (likely(wl->tx_blocks_freed <=
872 le32_to_cpu(status->total_released_blks)))
873 freed_blocks = le32_to_cpu(status->total_released_blks) -
874 wl->tx_blocks_freed;
875 else
876 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
877 le32_to_cpu(status->total_released_blks);
878
Eliad Peller4d56ad92011-08-14 13:17:05 +0300879 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200880
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300881 wl->tx_allocated_blocks -= freed_blocks;
882
Eliad Peller4d56ad92011-08-14 13:17:05 +0300883 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200884
Eliad Peller4d56ad92011-08-14 13:17:05 +0300885 /*
886 * The FW might change the total number of TX memblocks before
887 * we get a notification about blocks being released. Thus, the
888 * available blocks calculation might yield a temporary result
889 * which is lower than the actual available blocks. Keeping in
890 * mind that only blocks that were allocated can be moved from
891 * TX to RX, tx_blocks_available should never decrease here.
892 */
893 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
894 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300895
Ido Yariva5225502010-10-12 14:49:10 +0200896 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200897 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200898 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899
Eliad Peller4d56ad92011-08-14 13:17:05 +0300900 /* for AP update num of allocated TX blocks per link and ps status */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300901 if (wl->bss_type == BSS_TYPE_AP_BSS)
902 wl12xx_irq_update_links_status(wl, status);
Eliad Peller4d56ad92011-08-14 13:17:05 +0300903
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300904 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200905 getnstimeofday(&ts);
906 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
907 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300908}
909
Ido Yariva6208652011-03-01 15:14:41 +0200910static void wl1271_flush_deferred_work(struct wl1271 *wl)
911{
912 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200913
Ido Yariva6208652011-03-01 15:14:41 +0200914 /* Pass all received frames to the network stack */
915 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
916 ieee80211_rx_ni(wl->hw, skb);
917
918 /* Return sent skbs to the network stack */
919 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300920 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200921}
922
923static void wl1271_netstack_work(struct work_struct *work)
924{
925 struct wl1271 *wl =
926 container_of(work, struct wl1271, netstack_work);
927
928 do {
929 wl1271_flush_deferred_work(wl);
930 } while (skb_queue_len(&wl->deferred_rx_queue));
931}
932
933#define WL1271_IRQ_MAX_LOOPS 256
934
935irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300938 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200939 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200940 struct wl1271 *wl = (struct wl1271 *)cookie;
941 bool done = false;
942 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200943 unsigned long flags;
944
945 /* TX might be handled here, avoid redundant work */
946 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
947 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948
Ido Yariv341b7cd2011-03-31 10:07:01 +0200949 /*
950 * In case edge triggered interrupt must be used, we cannot iterate
951 * more than once without introducing race conditions with the hardirq.
952 */
953 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
954 loopcount = 1;
955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956 mutex_lock(&wl->mutex);
957
958 wl1271_debug(DEBUG_IRQ, "IRQ work");
959
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200960 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300961 goto out;
962
Ido Yariva6208652011-03-01 15:14:41 +0200963 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300964 if (ret < 0)
965 goto out;
966
Ido Yariva6208652011-03-01 15:14:41 +0200967 while (!done && loopcount--) {
968 /*
969 * In order to avoid a race with the hardirq, clear the flag
970 * before acknowledging the chip. Since the mutex is held,
971 * wl1271_ps_elp_wakeup cannot be called concurrently.
972 */
973 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
974 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200975
Eliad Peller4d56ad92011-08-14 13:17:05 +0300976 wl12xx_fw_status(wl, wl->fw_status);
977 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200978 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200979 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200980 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200981 continue;
982 }
983
Eliad Pellerccc83b02010-10-27 14:09:57 +0200984 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
985 wl1271_error("watchdog interrupt received! "
986 "starting recovery.");
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300987 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200988
989 /* restarting the chip. ignore any other interrupt. */
990 goto out;
991 }
992
Ido Yariva6208652011-03-01 15:14:41 +0200993 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200994 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
995
Eliad Peller4d56ad92011-08-14 13:17:05 +0300996 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200997
Ido Yariva5225502010-10-12 14:49:10 +0200998 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200999 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001000 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001001 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +02001002 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001003 /*
1004 * In order to avoid starvation of the TX path,
1005 * call the work function directly.
1006 */
1007 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +02001008 } else {
1009 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001010 }
1011
Ido Yariv8aad2462011-03-01 15:14:38 +02001012 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001013 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +02001014 (wl->tx_results_count & 0xff))
1015 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001016
1017 /* Make sure the deferred queues don't get too long */
1018 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1019 skb_queue_len(&wl->deferred_rx_queue);
1020 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1021 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001022 }
1023
1024 if (intr & WL1271_ACX_INTR_EVENT_A) {
1025 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1026 wl1271_event_handle(wl, 0);
1027 }
1028
1029 if (intr & WL1271_ACX_INTR_EVENT_B) {
1030 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1031 wl1271_event_handle(wl, 1);
1032 }
1033
1034 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1035 wl1271_debug(DEBUG_IRQ,
1036 "WL1271_ACX_INTR_INIT_COMPLETE");
1037
1038 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1039 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040 }
1041
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042 wl1271_ps_elp_sleep(wl);
1043
1044out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001045 spin_lock_irqsave(&wl->wl_lock, flags);
1046 /* In case TX was not handled here, queue TX work */
1047 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1048 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001049 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001050 ieee80211_queue_work(wl->hw, &wl->tx_work);
1051 spin_unlock_irqrestore(&wl->wl_lock, flags);
1052
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001054
1055 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056}
Ido Yariva6208652011-03-01 15:14:41 +02001057EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001059static int wl1271_fetch_firmware(struct wl1271 *wl)
1060{
1061 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001062 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001063 int ret;
1064
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001065 if (wl->chip.id == CHIP_ID_1283_PG20)
1066 fw_name = WL128X_FW_NAME;
1067 else
1068 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001069
1070 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1071
1072 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001073
1074 if (ret < 0) {
1075 wl1271_error("could not get firmware: %d", ret);
1076 return ret;
1077 }
1078
1079 if (fw->size % 4) {
1080 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1081 fw->size);
1082 ret = -EILSEQ;
1083 goto out;
1084 }
1085
Arik Nemtsov166d5042010-10-16 21:44:57 +02001086 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001087 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001088 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001089
1090 if (!wl->fw) {
1091 wl1271_error("could not allocate memory for the firmware");
1092 ret = -ENOMEM;
1093 goto out;
1094 }
1095
1096 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097 ret = 0;
1098
1099out:
1100 release_firmware(fw);
1101
1102 return ret;
1103}
1104
1105static int wl1271_fetch_nvs(struct wl1271 *wl)
1106{
1107 const struct firmware *fw;
1108 int ret;
1109
Shahar Levi5aa42342011-03-06 16:32:07 +02001110 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111
1112 if (ret < 0) {
1113 wl1271_error("could not get nvs file: %d", ret);
1114 return ret;
1115 }
1116
Shahar Levibc765bf2011-03-06 16:32:10 +02001117 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001118
1119 if (!wl->nvs) {
1120 wl1271_error("could not allocate memory for the nvs file");
1121 ret = -ENOMEM;
1122 goto out;
1123 }
1124
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001125 wl->nvs_len = fw->size;
1126
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001127out:
1128 release_firmware(fw);
1129
1130 return ret;
1131}
1132
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001133void wl12xx_queue_recovery_work(struct wl1271 *wl)
1134{
1135 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1136 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1137}
1138
Ido Yariv95dac04f2011-06-06 14:57:06 +03001139size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1140{
1141 size_t len = 0;
1142
1143 /* The FW log is a length-value list, find where the log end */
1144 while (len < maxlen) {
1145 if (memblock[len] == 0)
1146 break;
1147 if (len + memblock[len] + 1 > maxlen)
1148 break;
1149 len += memblock[len] + 1;
1150 }
1151
1152 /* Make sure we have enough room */
1153 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1154
1155 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1156 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1157 wl->fwlog_size += len;
1158
1159 return len;
1160}
1161
1162static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1163{
1164 u32 addr;
1165 u32 first_addr;
1166 u8 *block;
1167
1168 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1169 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1170 (wl->conf.fwlog.mem_blocks == 0))
1171 return;
1172
1173 wl1271_info("Reading FW panic log");
1174
1175 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1176 if (!block)
1177 return;
1178
1179 /*
1180 * Make sure the chip is awake and the logger isn't active.
1181 * This might fail if the firmware hanged.
1182 */
1183 if (!wl1271_ps_elp_wakeup(wl))
1184 wl12xx_cmd_stop_fwlog(wl);
1185
1186 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001187 wl12xx_fw_status(wl, wl->fw_status);
1188 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001189 if (!first_addr)
1190 goto out;
1191
1192 /* Traverse the memory blocks linked list */
1193 addr = first_addr;
1194 do {
1195 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1196 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1197 false);
1198
1199 /*
1200 * Memory blocks are linked to one another. The first 4 bytes
1201 * of each memory block hold the hardware address of the next
1202 * one. The last memory block points to the first one.
1203 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001204 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001205 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1206 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1207 break;
1208 } while (addr && (addr != first_addr));
1209
1210 wake_up_interruptible(&wl->fwlog_waitq);
1211
1212out:
1213 kfree(block);
1214}
1215
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001216static void wl1271_recovery_work(struct work_struct *work)
1217{
1218 struct wl1271 *wl =
1219 container_of(work, struct wl1271, recovery_work);
1220
1221 mutex_lock(&wl->mutex);
1222
1223 if (wl->state != WL1271_STATE_ON)
1224 goto out;
1225
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001226 /* Avoid a recursive recovery */
1227 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1228
Ido Yariv95dac04f2011-06-06 14:57:06 +03001229 wl12xx_read_fwlog_panic(wl);
1230
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001231 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1232 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001233
Eliad Peller2a5bff02011-08-25 18:10:59 +03001234 BUG_ON(bug_on_recovery);
1235
Oz Krakowskib992c682011-06-26 10:36:02 +03001236 /*
1237 * Advance security sequence number to overcome potential progress
1238 * in the firmware during recovery. This doens't hurt if the network is
1239 * not encrypted.
1240 */
1241 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1242 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1243 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1244
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001245 /* Prevent spurious TX during FW restart */
1246 ieee80211_stop_queues(wl->hw);
1247
Luciano Coelho33c2c062011-05-10 14:46:02 +03001248 if (wl->sched_scanning) {
1249 ieee80211_sched_scan_stopped(wl->hw);
1250 wl->sched_scanning = false;
1251 }
1252
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001253 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001254 __wl1271_op_remove_interface(wl, false);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001255
1256 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1257
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001258 ieee80211_restart_hw(wl->hw);
1259
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001260 /*
1261 * Its safe to enable TX now - the queues are stopped after a request
1262 * to restart the HW.
1263 */
1264 ieee80211_wake_queues(wl->hw);
1265
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001266out:
1267 mutex_unlock(&wl->mutex);
1268}
1269
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001270static void wl1271_fw_wakeup(struct wl1271 *wl)
1271{
1272 u32 elp_reg;
1273
1274 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001275 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001276}
1277
1278static int wl1271_setup(struct wl1271 *wl)
1279{
1280 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1281 if (!wl->fw_status)
1282 return -ENOMEM;
1283
1284 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1285 if (!wl->tx_res_if) {
1286 kfree(wl->fw_status);
1287 return -ENOMEM;
1288 }
1289
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001290 return 0;
1291}
1292
1293static int wl1271_chip_wakeup(struct wl1271 *wl)
1294{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001295 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296 int ret = 0;
1297
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001298 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001299 ret = wl1271_power_on(wl);
1300 if (ret < 0)
1301 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001302 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001303 wl1271_io_reset(wl);
1304 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001305
1306 /* We don't need a real memory partition here, because we only want
1307 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001308 memset(&partition, 0, sizeof(partition));
1309 partition.reg.start = REGISTERS_BASE;
1310 partition.reg.size = REGISTERS_DOWN_SIZE;
1311 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001312
1313 /* ELP module wake up */
1314 wl1271_fw_wakeup(wl);
1315
1316 /* whal_FwCtrl_BootSm() */
1317
1318 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001319 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001320
1321 /* 1. check if chip id is valid */
1322
1323 switch (wl->chip.id) {
1324 case CHIP_ID_1271_PG10:
1325 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1326 wl->chip.id);
1327
1328 ret = wl1271_setup(wl);
1329 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001330 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331 break;
1332 case CHIP_ID_1271_PG20:
1333 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1334 wl->chip.id);
1335
1336 ret = wl1271_setup(wl);
1337 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001338 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001340 case CHIP_ID_1283_PG20:
1341 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1342 wl->chip.id);
1343
1344 ret = wl1271_setup(wl);
1345 if (ret < 0)
1346 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001347
Ido Yariv0da13da2011-03-31 10:06:58 +02001348 if (wl1271_set_block_size(wl))
1349 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001350 break;
1351 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001352 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001353 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001354 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001355 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001356 }
1357
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001358 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359 ret = wl1271_fetch_firmware(wl);
1360 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001361 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362 }
1363
1364 /* No NVS from netlink, try to get it from the filesystem */
1365 if (wl->nvs == NULL) {
1366 ret = wl1271_fetch_nvs(wl);
1367 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001368 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001369 }
1370
1371out:
1372 return ret;
1373}
1374
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001375int wl1271_plt_start(struct wl1271 *wl)
1376{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001377 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001378 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001379 int ret;
1380
1381 mutex_lock(&wl->mutex);
1382
1383 wl1271_notice("power up");
1384
1385 if (wl->state != WL1271_STATE_OFF) {
1386 wl1271_error("cannot go into PLT state because not "
1387 "in off state: %d", wl->state);
1388 ret = -EBUSY;
1389 goto out;
1390 }
1391
Arik Nemtsov166d5042010-10-16 21:44:57 +02001392 wl->bss_type = BSS_TYPE_STA_BSS;
1393
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001394 while (retries) {
1395 retries--;
1396 ret = wl1271_chip_wakeup(wl);
1397 if (ret < 0)
1398 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001399
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001400 ret = wl1271_boot(wl);
1401 if (ret < 0)
1402 goto power_off;
1403
1404 ret = wl1271_plt_init(wl);
1405 if (ret < 0)
1406 goto irq_disable;
1407
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001408 wl->state = WL1271_STATE_PLT;
1409 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001410 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001411
Gery Kahn6f07b722011-07-18 14:21:49 +03001412 /* update hw/fw version info in wiphy struct */
1413 wiphy->hw_version = wl->chip.id;
1414 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1415 sizeof(wiphy->fw_version));
1416
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001417 goto out;
1418
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001419irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001420 mutex_unlock(&wl->mutex);
1421 /* Unlocking the mutex in the middle of handling is
1422 inherently unsafe. In this case we deem it safe to do,
1423 because we need to let any possibly pending IRQ out of
1424 the system (and while we are WL1271_STATE_OFF the IRQ
1425 work function will not do anything.) Also, any other
1426 possible concurrent operations will fail due to the
1427 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001428 wl1271_disable_interrupts(wl);
1429 wl1271_flush_deferred_work(wl);
1430 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001431 mutex_lock(&wl->mutex);
1432power_off:
1433 wl1271_power_off(wl);
1434 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001435
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001436 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1437 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438out:
1439 mutex_unlock(&wl->mutex);
1440
1441 return ret;
1442}
1443
Luciano Coelho4623ec72011-03-21 19:26:41 +02001444static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001445{
1446 int ret = 0;
1447
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448 wl1271_notice("power down");
1449
1450 if (wl->state != WL1271_STATE_PLT) {
1451 wl1271_error("cannot power down because not in PLT "
1452 "state: %d", wl->state);
1453 ret = -EBUSY;
1454 goto out;
1455 }
1456
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001457 wl1271_power_off(wl);
1458
1459 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001460 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001461
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001462 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001463 wl1271_disable_interrupts(wl);
1464 wl1271_flush_deferred_work(wl);
1465 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001466 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001467 mutex_lock(&wl->mutex);
1468out:
1469 return ret;
1470}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001471
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001472int wl1271_plt_stop(struct wl1271 *wl)
1473{
1474 int ret;
1475
1476 mutex_lock(&wl->mutex);
1477 ret = __wl1271_plt_stop(wl);
1478 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001479 return ret;
1480}
1481
Johannes Berg7bb45682011-02-24 14:42:06 +01001482static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001483{
1484 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001485 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001486 int q, mapping;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001487 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001488
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001489 mapping = skb_get_queue_mapping(skb);
1490 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001491
1492 if (wl->bss_type == BSS_TYPE_AP_BSS)
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03001493 hlid = wl12xx_tx_get_hlid_ap(wl, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001494
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001495 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001496
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001497 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001498 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov04216da2011-08-14 13:17:38 +03001499 if (!wl1271_is_active_sta(wl, hlid)) {
1500 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d",
1501 hlid, q);
1502 dev_kfree_skb(skb);
1503 goto out;
1504 }
1505
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001506 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1507 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1508 } else {
1509 skb_queue_tail(&wl->tx_queue[q], skb);
1510 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001511
Arik Nemtsov04b4d69c2011-08-14 13:17:39 +03001512 wl->tx_queue_count[q]++;
1513
1514 /*
1515 * The workqueue is slow to process the tx_queue and we need stop
1516 * the queue here, otherwise the queue will get too long.
1517 */
1518 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1519 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1520 ieee80211_stop_queue(wl->hw, mapping);
1521 set_bit(q, &wl->stopped_queues_map);
1522 }
1523
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001524 /*
1525 * The chip specific setup must run before the first TX packet -
1526 * before that, the tx_work will not be initialized!
1527 */
1528
Ido Yarivb07d4032011-03-01 15:14:43 +02001529 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1530 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001531 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001532
Arik Nemtsov04216da2011-08-14 13:17:38 +03001533out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001534 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001535}
1536
Shahar Leviae47c452011-03-06 16:32:14 +02001537int wl1271_tx_dummy_packet(struct wl1271 *wl)
1538{
Ido Yariv990f5de2011-03-31 10:06:59 +02001539 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001540 int q;
1541
1542 /* no need to queue a new dummy packet if one is already pending */
1543 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1544 return 0;
1545
1546 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001547
Ido Yariv990f5de2011-03-31 10:06:59 +02001548 spin_lock_irqsave(&wl->wl_lock, flags);
1549 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001550 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001551 spin_unlock_irqrestore(&wl->wl_lock, flags);
1552
1553 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1554 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1555 wl1271_tx_work_locked(wl);
1556
1557 /*
1558 * If the FW TX is busy, TX work will be scheduled by the threaded
1559 * interrupt handler function
1560 */
1561 return 0;
1562}
1563
1564/*
1565 * The size of the dummy packet should be at least 1400 bytes. However, in
1566 * order to minimize the number of bus transactions, aligning it to 512 bytes
1567 * boundaries could be beneficial, performance wise
1568 */
1569#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1570
Luciano Coelhocf27d862011-04-01 21:08:23 +03001571static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001572{
1573 struct sk_buff *skb;
1574 struct ieee80211_hdr_3addr *hdr;
1575 unsigned int dummy_packet_size;
1576
1577 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1578 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1579
1580 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001581 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001582 wl1271_warning("Failed to allocate a dummy packet skb");
1583 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001584 }
1585
1586 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1587
1588 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1589 memset(hdr, 0, sizeof(*hdr));
1590 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001591 IEEE80211_STYPE_NULLFUNC |
1592 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001593
Ido Yariv990f5de2011-03-31 10:06:59 +02001594 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001595
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001596 /* Dummy packets require the TID to be management */
1597 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001598
1599 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001600 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001601 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001602
Ido Yariv990f5de2011-03-31 10:06:59 +02001603 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001604}
1605
Ido Yariv990f5de2011-03-31 10:06:59 +02001606
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001607static struct notifier_block wl1271_dev_notifier = {
1608 .notifier_call = wl1271_dev_notify,
1609};
1610
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001611#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001612static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1613 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001614{
Eliad Pellere85d1622011-06-27 13:06:43 +03001615 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001616
Eliad Peller94390642011-05-13 11:57:13 +03001617 mutex_lock(&wl->mutex);
1618
Eliad Pellere85d1622011-06-27 13:06:43 +03001619 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1620 goto out_unlock;
1621
Eliad Peller94390642011-05-13 11:57:13 +03001622 ret = wl1271_ps_elp_wakeup(wl);
1623 if (ret < 0)
1624 goto out_unlock;
1625
1626 /* enter psm if needed*/
1627 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1628 DECLARE_COMPLETION_ONSTACK(compl);
1629
1630 wl->ps_compl = &compl;
1631 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001632 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001633 if (ret < 0)
1634 goto out_sleep;
1635
1636 /* we must unlock here so we will be able to get events */
1637 wl1271_ps_elp_sleep(wl);
1638 mutex_unlock(&wl->mutex);
1639
1640 ret = wait_for_completion_timeout(
1641 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1642 if (ret <= 0) {
1643 wl1271_warning("couldn't enter ps mode!");
1644 ret = -EBUSY;
1645 goto out;
1646 }
1647
1648 /* take mutex again, and wakeup */
1649 mutex_lock(&wl->mutex);
1650
1651 ret = wl1271_ps_elp_wakeup(wl);
1652 if (ret < 0)
1653 goto out_unlock;
1654 }
1655out_sleep:
1656 wl1271_ps_elp_sleep(wl);
1657out_unlock:
1658 mutex_unlock(&wl->mutex);
1659out:
1660 return ret;
1661
1662}
1663
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001664static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001665{
Eliad Pellere85d1622011-06-27 13:06:43 +03001666 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001667
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001668 mutex_lock(&wl->mutex);
1669
Eliad Pellere85d1622011-06-27 13:06:43 +03001670 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1671 goto out_unlock;
1672
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001673 ret = wl1271_ps_elp_wakeup(wl);
1674 if (ret < 0)
1675 goto out_unlock;
1676
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001677 ret = wl1271_acx_beacon_filter_opt(wl, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001678
1679 wl1271_ps_elp_sleep(wl);
1680out_unlock:
1681 mutex_unlock(&wl->mutex);
1682 return ret;
1683
1684}
1685
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001686static int wl1271_configure_suspend(struct wl1271 *wl,
1687 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001688{
1689 if (wl->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001690 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001691 if (wl->bss_type == BSS_TYPE_AP_BSS)
1692 return wl1271_configure_suspend_ap(wl);
1693 return 0;
1694}
1695
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001696static void wl1271_configure_resume(struct wl1271 *wl,
1697 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001698{
1699 int ret;
1700 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1701 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1702
1703 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001704 return;
1705
1706 mutex_lock(&wl->mutex);
1707 ret = wl1271_ps_elp_wakeup(wl);
1708 if (ret < 0)
1709 goto out;
1710
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001711 if (is_sta) {
1712 /* exit psm if it wasn't configured */
1713 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1714 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001715 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001716 } else if (is_ap) {
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001717 wl1271_acx_beacon_filter_opt(wl, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001718 }
Eliad Peller94390642011-05-13 11:57:13 +03001719
1720 wl1271_ps_elp_sleep(wl);
1721out:
1722 mutex_unlock(&wl->mutex);
1723}
1724
Eliad Peller402e48612011-05-13 11:57:09 +03001725static int wl1271_op_suspend(struct ieee80211_hw *hw,
1726 struct cfg80211_wowlan *wow)
1727{
1728 struct wl1271 *wl = hw->priv;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001729 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
1730 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001731 int ret;
1732
Eliad Peller402e48612011-05-13 11:57:09 +03001733 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001734 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001735
Eliad Peller4a859df2011-06-06 12:21:52 +03001736 wl->wow_enabled = true;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001737 ret = wl1271_configure_suspend(wl, wlvif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001738 if (ret < 0) {
1739 wl1271_warning("couldn't prepare device to suspend");
1740 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001741 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001742 /* flush any remaining work */
1743 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001744
1745 /*
1746 * disable and re-enable interrupts in order to flush
1747 * the threaded_irq
1748 */
1749 wl1271_disable_interrupts(wl);
1750
1751 /*
1752 * set suspended flag to avoid triggering a new threaded_irq
1753 * work. no need for spinlock as interrupts are disabled.
1754 */
1755 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1756
1757 wl1271_enable_interrupts(wl);
1758 flush_work(&wl->tx_work);
1759 flush_delayed_work(&wl->pspoll_work);
1760 flush_delayed_work(&wl->elp_work);
1761
Eliad Peller402e48612011-05-13 11:57:09 +03001762 return 0;
1763}
1764
1765static int wl1271_op_resume(struct ieee80211_hw *hw)
1766{
1767 struct wl1271 *wl = hw->priv;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001768 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
1769 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001770 unsigned long flags;
1771 bool run_irq_work = false;
1772
Eliad Peller402e48612011-05-13 11:57:09 +03001773 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1774 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001775 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001776
1777 /*
1778 * re-enable irq_work enqueuing, and call irq_work directly if
1779 * there is a pending work.
1780 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001781 spin_lock_irqsave(&wl->wl_lock, flags);
1782 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1783 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1784 run_irq_work = true;
1785 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001786
Eliad Peller4a859df2011-06-06 12:21:52 +03001787 if (run_irq_work) {
1788 wl1271_debug(DEBUG_MAC80211,
1789 "run postponed irq_work directly");
1790 wl1271_irq(0, wl);
1791 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001792 }
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001793 wl1271_configure_resume(wl, wlvif);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001794 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001795
Eliad Peller402e48612011-05-13 11:57:09 +03001796 return 0;
1797}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001798#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001799
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001800static int wl1271_op_start(struct ieee80211_hw *hw)
1801{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001802 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1803
1804 /*
1805 * We have to delay the booting of the hardware because
1806 * we need to know the local MAC address before downloading and
1807 * initializing the firmware. The MAC address cannot be changed
1808 * after boot, and without the proper MAC address, the firmware
1809 * will not function properly.
1810 *
1811 * The MAC address is first known when the corresponding interface
1812 * is added. That is where we will initialize the hardware.
1813 */
1814
1815 return 0;
1816}
1817
1818static void wl1271_op_stop(struct ieee80211_hw *hw)
1819{
1820 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1821}
1822
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001823static u8 wl12xx_get_role_type(struct wl1271 *wl)
1824{
1825 switch (wl->bss_type) {
1826 case BSS_TYPE_AP_BSS:
Eliad Peller045c7452011-08-28 15:23:01 +03001827 if (wl->p2p)
1828 return WL1271_ROLE_P2P_GO;
1829 else
1830 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001831
1832 case BSS_TYPE_STA_BSS:
Eliad Peller045c7452011-08-28 15:23:01 +03001833 if (wl->p2p)
1834 return WL1271_ROLE_P2P_CL;
1835 else
1836 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001837
Eliad Peller227e81e2011-08-14 13:17:26 +03001838 case BSS_TYPE_IBSS:
1839 return WL1271_ROLE_IBSS;
1840
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001841 default:
1842 wl1271_error("invalid bss_type: %d", wl->bss_type);
1843 }
1844 return WL12XX_INVALID_ROLE_TYPE;
1845}
1846
Eliad Peller87fbcb02011-10-05 11:55:41 +02001847static void wl12xx_init_vif_data(struct wl12xx_vif *wlvif)
1848{
1849 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001850 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001851 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001852}
1853
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001854static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1855 struct ieee80211_vif *vif)
1856{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001857 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001858 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001859 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001860 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001861 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02001862 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001863
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001864 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03001865 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001866
1867 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001868 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001869 wl1271_debug(DEBUG_MAC80211,
1870 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001871 ret = -EBUSY;
1872 goto out;
1873 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02001874 wl12xx_init_vif_data(wl12xx_vif_to_data(vif));
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001875
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001876 /*
1877 * in some very corner case HW recovery scenarios its possible to
1878 * get here before __wl1271_op_remove_interface is complete, so
1879 * opt out if that is the case.
1880 */
1881 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1882 ret = -EBUSY;
1883 goto out;
1884 }
1885
Eliad Peller045c7452011-08-28 15:23:01 +03001886 switch (ieee80211_vif_type_p2p(vif)) {
1887 case NL80211_IFTYPE_P2P_CLIENT:
1888 wl->p2p = 1;
1889 /* fall-through */
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001890 case NL80211_IFTYPE_STATION:
1891 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001892 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001893 break;
1894 case NL80211_IFTYPE_ADHOC:
1895 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001896 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001897 break;
Eliad Peller045c7452011-08-28 15:23:01 +03001898 case NL80211_IFTYPE_P2P_GO:
1899 wl->p2p = 1;
1900 /* fall-through */
Arik Nemtsov038d9252010-10-16 21:53:24 +02001901 case NL80211_IFTYPE_AP:
1902 wl->bss_type = BSS_TYPE_AP_BSS;
1903 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001904 default:
1905 ret = -EOPNOTSUPP;
1906 goto out;
1907 }
1908
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001909 role_type = wl12xx_get_role_type(wl);
1910 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
1911 ret = -EINVAL;
1912 goto out;
1913 }
Eliad Peller784f6942011-10-05 11:55:39 +02001914 /*
1915 * we still need this in order to configure the fw
1916 * while uploading the nvs
1917 */
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001918 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001919
1920 if (wl->state != WL1271_STATE_OFF) {
1921 wl1271_error("cannot start because not in off state: %d",
1922 wl->state);
1923 ret = -EBUSY;
1924 goto out;
1925 }
1926
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001927 while (retries) {
1928 retries--;
1929 ret = wl1271_chip_wakeup(wl);
1930 if (ret < 0)
1931 goto power_off;
1932
1933 ret = wl1271_boot(wl);
1934 if (ret < 0)
1935 goto power_off;
1936
Eliad Peller92c77c72011-10-05 11:55:40 +02001937 ret = wl1271_hw_init(wl);
1938 if (ret < 0)
1939 goto irq_disable;
1940
Eliad Peller227e81e2011-08-14 13:17:26 +03001941 if (wl->bss_type == BSS_TYPE_STA_BSS ||
1942 wl->bss_type == BSS_TYPE_IBSS) {
Eliad Peller04e80792011-08-14 13:17:09 +03001943 /*
1944 * The device role is a special role used for
1945 * rx and tx frames prior to association (as
1946 * the STA role can get packets only from
1947 * its associated bssid)
1948 */
Eliad Peller784f6942011-10-05 11:55:39 +02001949 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller04e80792011-08-14 13:17:09 +03001950 WL1271_ROLE_DEVICE,
1951 &wl->dev_role_id);
1952 if (ret < 0)
1953 goto irq_disable;
1954 }
1955
Eliad Peller784f6942011-10-05 11:55:39 +02001956 ret = wl12xx_cmd_role_enable(wl, vif->addr,
1957 role_type, &wl->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001958 if (ret < 0)
1959 goto irq_disable;
1960
Eliad Peller92c77c72011-10-05 11:55:40 +02001961 ret = wl1271_init_vif_specific(wl, vif);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001962 if (ret < 0)
1963 goto irq_disable;
1964
Eliad Peller71125ab2010-10-28 21:46:43 +02001965 booted = true;
1966 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001968irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001969 mutex_unlock(&wl->mutex);
1970 /* Unlocking the mutex in the middle of handling is
1971 inherently unsafe. In this case we deem it safe to do,
1972 because we need to let any possibly pending IRQ out of
1973 the system (and while we are WL1271_STATE_OFF the IRQ
1974 work function will not do anything.) Also, any other
1975 possible concurrent operations will fail due to the
1976 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001977 wl1271_disable_interrupts(wl);
1978 wl1271_flush_deferred_work(wl);
1979 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001980 mutex_lock(&wl->mutex);
1981power_off:
1982 wl1271_power_off(wl);
1983 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001984
Eliad Peller71125ab2010-10-28 21:46:43 +02001985 if (!booted) {
1986 wl1271_error("firmware boot failed despite %d retries",
1987 WL1271_BOOT_RETRIES);
1988 goto out;
1989 }
1990
1991 wl->vif = vif;
1992 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001993 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001994 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001995
1996 /* update hw/fw version info in wiphy struct */
1997 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001998 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001999 sizeof(wiphy->fw_version));
2000
Luciano Coelhofb6a6812010-12-03 17:05:40 +02002001 /*
2002 * Now we know if 11a is supported (info from the NVS), so disable
2003 * 11a channels if not supported
2004 */
2005 if (!wl->enable_11a)
2006 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2007
2008 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2009 wl->enable_11a ? "" : "not ");
2010
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002011out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002012 mutex_unlock(&wl->mutex);
2013
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002014 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002015 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002016 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002017 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002018
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002019 return ret;
2020}
2021
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002022static void __wl1271_op_remove_interface(struct wl1271 *wl,
2023 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002024{
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002025 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002026
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002027 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002028
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002029 /* because of hardware recovery, we may get here twice */
2030 if (wl->state != WL1271_STATE_ON)
2031 return;
2032
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002033 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002034
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002035 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002036 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002037 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002038
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002039 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03002040 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002041 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002042
Luciano Coelho08688d62010-07-08 17:50:07 +03002043 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002044 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002045 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002046 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002047 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002048 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002049 }
2050
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002051 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2052 /* disable active roles */
2053 ret = wl1271_ps_elp_wakeup(wl);
2054 if (ret < 0)
2055 goto deinit;
2056
Eliad Peller04e80792011-08-14 13:17:09 +03002057 if (wl->bss_type == BSS_TYPE_STA_BSS) {
2058 ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
2059 if (ret < 0)
2060 goto deinit;
2061 }
2062
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002063 ret = wl12xx_cmd_role_disable(wl, &wl->role_id);
2064 if (ret < 0)
2065 goto deinit;
2066
2067 wl1271_ps_elp_sleep(wl);
2068 }
2069deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002070 /* clear all hlids (except system_hlid) */
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002071 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002072 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002073 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
2074 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002075
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002076 /*
2077 * this must be before the cancel_work calls below, so that the work
2078 * functions don't perform further work.
2079 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002080 wl->state = WL1271_STATE_OFF;
2081
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002082 mutex_unlock(&wl->mutex);
2083
Ido Yariva6208652011-03-01 15:14:41 +02002084 wl1271_disable_interrupts(wl);
2085 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02002086 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02002087 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002088 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03002089 del_timer_sync(&wl->rx_streaming_timer);
2090 cancel_work_sync(&wl->rx_streaming_enable_work);
2091 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002092 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02002093 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002094
2095 mutex_lock(&wl->mutex);
2096
2097 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002098 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002099 wl1271_power_off(wl);
2100
2101 memset(wl->bssid, 0, ETH_ALEN);
Johannes Berg3b40c042011-07-13 10:39:16 +02002102 memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002103 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002104 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002105 wl->set_bss_type = MAX_BSS_TYPE;
Eliad Peller045c7452011-08-28 15:23:01 +03002106 wl->p2p = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002107 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002108
2109 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002110 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002111 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
2112 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002113 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002114 wl->tx_results_count = 0;
2115 wl->tx_packets_count = 0;
2116 wl->time_offset = 0;
2117 wl->session_counter = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03002118 wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
2119 wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002120 wl->vif = NULL;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002121 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002122 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002123 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02002124 wl->ap_fw_ps_map = 0;
2125 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002126 wl->sched_scanning = false;
Eliad Peller7f0979882011-08-14 13:17:06 +03002127 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002128 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerc690ec82011-08-14 13:17:07 +03002129 memset(wl->roles_map, 0, sizeof(wl->roles_map));
2130 memset(wl->links_map, 0, sizeof(wl->links_map));
Eliad Peller251c1772011-08-14 13:17:17 +03002131 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Arik Nemtsovda032092011-08-25 12:43:15 +03002132 wl->active_sta_count = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03002133
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002134 /* The system link is always allocated */
2135 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
2136
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002137 /*
2138 * this is performed after the cancel_work calls and the associated
2139 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2140 * get executed before all these vars have been reset.
2141 */
2142 wl->flags = 0;
2143
Eliad Peller4d56ad92011-08-14 13:17:05 +03002144 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002145
Arik Nemtsov742246f2011-08-14 13:17:33 +03002146 for (i = 0; i < NUM_TX_QUEUES; i++) {
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002147 wl->tx_pkts_freed[i] = 0;
Arik Nemtsov742246f2011-08-14 13:17:33 +03002148 wl->tx_allocated_pkts[i] = 0;
2149 }
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002150
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002151 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002152
2153 kfree(wl->fw_status);
2154 wl->fw_status = NULL;
2155 kfree(wl->tx_res_if);
2156 wl->tx_res_if = NULL;
2157 kfree(wl->target_mem_map);
2158 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002159}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002160
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002161static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2162 struct ieee80211_vif *vif)
2163{
2164 struct wl1271 *wl = hw->priv;
2165
2166 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002167 /*
2168 * wl->vif can be null here if someone shuts down the interface
2169 * just when hardware recovery has been started.
2170 */
2171 if (wl->vif) {
2172 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002173 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002174 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002175
Juuso Oikarinen67353292010-11-18 15:19:02 +02002176 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002177 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002178}
2179
Eliad Peller87fbcb02011-10-05 11:55:41 +02002180static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2181 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002182{
2183 int ret;
Eliad Peller227e81e2011-08-14 13:17:26 +03002184 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002185
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002186 /*
2187 * One of the side effects of the JOIN command is that is clears
2188 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2189 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002190 * Currently the only valid scenario for JOIN during association
2191 * is on roaming, in which case we will also be given new keys.
2192 * Keep the below message for now, unless it starts bothering
2193 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002194 */
2195 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2196 wl1271_info("JOIN while associated.");
2197
2198 if (set_assoc)
2199 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2200
Eliad Peller227e81e2011-08-14 13:17:26 +03002201 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002202 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002203 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002204 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002205 if (ret < 0)
2206 goto out;
2207
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002208 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2209 goto out;
2210
2211 /*
2212 * The join command disable the keep-alive mode, shut down its process,
2213 * and also clear the template config, so we need to reset it all after
2214 * the join. The acx_aid starts the keep-alive process, and the order
2215 * of the commands below is relevant.
2216 */
2217 ret = wl1271_acx_keep_alive_mode(wl, true);
2218 if (ret < 0)
2219 goto out;
2220
2221 ret = wl1271_acx_aid(wl, wl->aid);
2222 if (ret < 0)
2223 goto out;
2224
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002225 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002226 if (ret < 0)
2227 goto out;
2228
2229 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2230 ACX_KEEP_ALIVE_TPL_VALID);
2231 if (ret < 0)
2232 goto out;
2233
2234out:
2235 return ret;
2236}
2237
2238static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002239{
2240 int ret;
2241
Shahar Levi6d158ff2011-09-08 13:01:33 +03002242 if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags)) {
2243 wl12xx_cmd_stop_channel_switch(wl);
2244 ieee80211_chswitch_done(wl->vif, false);
2245 }
2246
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002247 /* to stop listening to a channel, we disconnect */
Eliad Pellerc690ec82011-08-14 13:17:07 +03002248 ret = wl12xx_cmd_role_stop_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002249 if (ret < 0)
2250 goto out;
2251
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002252 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002253
Oz Krakowskib992c682011-06-26 10:36:02 +03002254 /* reset TX security counters on a clean disconnect */
2255 wl->tx_security_last_seq_lsb = 0;
2256 wl->tx_security_seq = 0;
2257
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002258out:
2259 return ret;
2260}
2261
Eliad Peller87fbcb02011-10-05 11:55:41 +02002262static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002263{
Eliad Peller87fbcb02011-10-05 11:55:41 +02002264 wlvif->basic_rate_set = wl->bitrate_masks[wl->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002265 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002266}
2267
Eliad Peller251c1772011-08-14 13:17:17 +03002268static bool wl12xx_is_roc(struct wl1271 *wl)
2269{
2270 u8 role_id;
2271
2272 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2273 if (role_id >= WL12XX_MAX_ROLES)
2274 return false;
2275
2276 return true;
2277}
2278
Eliad Peller87fbcb02011-10-05 11:55:41 +02002279static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2280 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002281{
2282 int ret;
2283
2284 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002285 /* no need to croc if we weren't busy (e.g. during boot) */
2286 if (wl12xx_is_roc(wl)) {
2287 ret = wl12xx_croc(wl, wl->dev_role_id);
2288 if (ret < 0)
2289 goto out;
2290
2291 ret = wl12xx_cmd_role_stop_dev(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002292 if (ret < 0)
2293 goto out;
2294 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002295 wlvif->rate_set =
2296 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2297 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002298 if (ret < 0)
2299 goto out;
2300 ret = wl1271_acx_keep_alive_config(
2301 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2302 ACX_KEEP_ALIVE_TPL_INVALID);
2303 if (ret < 0)
2304 goto out;
2305 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2306 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002307 /* The current firmware only supports sched_scan in idle */
2308 if (wl->sched_scanning) {
2309 wl1271_scan_sched_scan_stop(wl);
2310 ieee80211_sched_scan_stopped(wl->hw);
2311 }
2312
Eliad Peller251c1772011-08-14 13:17:17 +03002313 ret = wl12xx_cmd_role_start_dev(wl);
2314 if (ret < 0)
2315 goto out;
2316
2317 ret = wl12xx_roc(wl, wl->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002318 if (ret < 0)
2319 goto out;
2320 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2321 }
2322
2323out:
2324 return ret;
2325}
2326
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002327static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2328{
2329 struct wl1271 *wl = hw->priv;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002330 struct ieee80211_vif *vif = wl->vif; /* TODO: reconfig all vifs */
2331 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002332 struct ieee80211_conf *conf = &hw->conf;
2333 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002334 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002335
2336 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2337
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002338 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2339 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002340 channel,
2341 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002342 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002343 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2344 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002345
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002346 /*
2347 * mac80211 will go to idle nearly immediately after transmitting some
2348 * frames, such as the deauth. To make sure those frames reach the air,
2349 * wait here until the TX queue is fully flushed.
2350 */
2351 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2352 (conf->flags & IEEE80211_CONF_IDLE))
2353 wl1271_tx_flush(wl);
2354
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002355 mutex_lock(&wl->mutex);
2356
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002357 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002358 /* we support configuring the channel and band while off */
2359 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2360 wl->band = conf->channel->band;
2361 wl->channel = channel;
2362 }
2363
Arik Nemtsov097f8822011-06-27 22:06:34 +03002364 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2365 wl->power_level = conf->power_level;
2366
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002367 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002368 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002369
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002370 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2371
Ido Yariva6208652011-03-01 15:14:41 +02002372 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002373 if (ret < 0)
2374 goto out;
2375
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002376 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002377 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2378 ((wl->band != conf->channel->band) ||
2379 (wl->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002380 /* send all pending packets */
2381 wl1271_tx_work_locked(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002382 wl->band = conf->channel->band;
2383 wl->channel = channel;
2384
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002385 if (!is_ap) {
2386 /*
2387 * FIXME: the mac80211 should really provide a fixed
2388 * rate to use here. for now, just use the smallest
2389 * possible rate for the band as a fixed rate for
2390 * association frames and other control messages.
2391 */
2392 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002393 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002394
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002395 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002396 wl1271_tx_min_rate_get(wl,
2397 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002398 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002399 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002400 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002401 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002402
Eliad Peller251c1772011-08-14 13:17:17 +03002403 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2404 if (wl12xx_is_roc(wl)) {
2405 /* roaming */
2406 ret = wl12xx_croc(wl, wl->dev_role_id);
2407 if (ret < 0)
2408 goto out_sleep;
2409 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002410 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002411 if (ret < 0)
2412 wl1271_warning("cmd join on channel "
2413 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002414 } else {
2415 /*
2416 * change the ROC channel. do it only if we are
2417 * not idle. otherwise, CROC will be called
2418 * anyway.
2419 */
2420 if (wl12xx_is_roc(wl) &&
2421 !(conf->flags & IEEE80211_CONF_IDLE)) {
2422 ret = wl12xx_croc(wl, wl->dev_role_id);
2423 if (ret < 0)
2424 goto out_sleep;
2425
2426 ret = wl12xx_roc(wl, wl->dev_role_id);
2427 if (ret < 0)
2428 wl1271_warning("roc failed %d",
2429 ret);
2430 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002431 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002432 }
2433 }
2434
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002435 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002436 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002437 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002438 if (ret < 0)
2439 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002440 }
2441
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002442 /*
2443 * if mac80211 changes the PSM mode, make sure the mode is not
2444 * incorrectly changed after the pspoll failure active window.
2445 */
2446 if (changed & IEEE80211_CONF_CHANGE_PS)
2447 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2448
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002449 if (conf->flags & IEEE80211_CONF_PS &&
2450 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2451 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002452
2453 /*
2454 * We enter PSM only if we're already associated.
2455 * If we're not, we'll enter it when joining an SSID,
2456 * through the bss_info_changed() hook.
2457 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002458 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002459 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002460 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002461 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002462 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002463 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002464 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002465 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002466
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002467 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002468
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002469 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002470 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002471 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002472 }
2473
2474 if (conf->power_level != wl->power_level) {
2475 ret = wl1271_acx_tx_power(wl, conf->power_level);
2476 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002477 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002478
2479 wl->power_level = conf->power_level;
2480 }
2481
2482out_sleep:
2483 wl1271_ps_elp_sleep(wl);
2484
2485out:
2486 mutex_unlock(&wl->mutex);
2487
2488 return ret;
2489}
2490
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002491struct wl1271_filter_params {
2492 bool enabled;
2493 int mc_list_length;
2494 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2495};
2496
Jiri Pirko22bedad32010-04-01 21:22:57 +00002497static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2498 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002499{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002500 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002501 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002502 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002503
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002504 if (unlikely(wl->state == WL1271_STATE_OFF))
2505 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002506
Juuso Oikarinen74441132009-10-13 12:47:53 +03002507 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002508 if (!fp) {
2509 wl1271_error("Out of memory setting filters.");
2510 return 0;
2511 }
2512
2513 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002514 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002515 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2516 fp->enabled = false;
2517 } else {
2518 fp->enabled = true;
2519 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002520 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002521 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002522 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002523 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002524 }
2525
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002526 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002527}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002528
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002529#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2530 FIF_ALLMULTI | \
2531 FIF_FCSFAIL | \
2532 FIF_BCN_PRBRESP_PROMISC | \
2533 FIF_CONTROL | \
2534 FIF_OTHER_BSS)
2535
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002536static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2537 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002538 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002539{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002540 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002541 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002542 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002543
Arik Nemtsov7d057862010-10-16 19:25:35 +02002544 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2545 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002546
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002547 mutex_lock(&wl->mutex);
2548
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002549 *total &= WL1271_SUPPORTED_FILTERS;
2550 changed &= WL1271_SUPPORTED_FILTERS;
2551
2552 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002553 goto out;
2554
Ido Yariva6208652011-03-01 15:14:41 +02002555 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002556 if (ret < 0)
2557 goto out;
2558
Arik Nemtsov7d057862010-10-16 19:25:35 +02002559 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2560 if (*total & FIF_ALLMULTI)
2561 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2562 else if (fp)
2563 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2564 fp->mc_list,
2565 fp->mc_list_length);
2566 if (ret < 0)
2567 goto out_sleep;
2568 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002569
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002570 /*
2571 * the fw doesn't provide an api to configure the filters. instead,
2572 * the filters configuration is based on the active roles / ROC
2573 * state.
2574 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002575
2576out_sleep:
2577 wl1271_ps_elp_sleep(wl);
2578
2579out:
2580 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002581 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002582}
2583
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002584static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2585 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2586 u16 tx_seq_16)
2587{
2588 struct wl1271_ap_key *ap_key;
2589 int i;
2590
2591 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2592
2593 if (key_size > MAX_KEY_SIZE)
2594 return -EINVAL;
2595
2596 /*
2597 * Find next free entry in ap_keys. Also check we are not replacing
2598 * an existing key.
2599 */
2600 for (i = 0; i < MAX_NUM_KEYS; i++) {
2601 if (wl->recorded_ap_keys[i] == NULL)
2602 break;
2603
2604 if (wl->recorded_ap_keys[i]->id == id) {
2605 wl1271_warning("trying to record key replacement");
2606 return -EINVAL;
2607 }
2608 }
2609
2610 if (i == MAX_NUM_KEYS)
2611 return -EBUSY;
2612
2613 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2614 if (!ap_key)
2615 return -ENOMEM;
2616
2617 ap_key->id = id;
2618 ap_key->key_type = key_type;
2619 ap_key->key_size = key_size;
2620 memcpy(ap_key->key, key, key_size);
2621 ap_key->hlid = hlid;
2622 ap_key->tx_seq_32 = tx_seq_32;
2623 ap_key->tx_seq_16 = tx_seq_16;
2624
2625 wl->recorded_ap_keys[i] = ap_key;
2626 return 0;
2627}
2628
2629static void wl1271_free_ap_keys(struct wl1271 *wl)
2630{
2631 int i;
2632
2633 for (i = 0; i < MAX_NUM_KEYS; i++) {
2634 kfree(wl->recorded_ap_keys[i]);
2635 wl->recorded_ap_keys[i] = NULL;
2636 }
2637}
2638
2639static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2640{
2641 int i, ret = 0;
2642 struct wl1271_ap_key *key;
2643 bool wep_key_added = false;
2644
2645 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002646 u8 hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002647 if (wl->recorded_ap_keys[i] == NULL)
2648 break;
2649
2650 key = wl->recorded_ap_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002651 hlid = key->hlid;
2652 if (hlid == WL12XX_INVALID_LINK_ID)
2653 hlid = wl->ap_bcast_hlid;
2654
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002655 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2656 key->id, key->key_type,
2657 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002658 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002659 key->tx_seq_16);
2660 if (ret < 0)
2661 goto out;
2662
2663 if (key->key_type == KEY_WEP)
2664 wep_key_added = true;
2665 }
2666
2667 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002668 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002669 wl->ap_bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002670 if (ret < 0)
2671 goto out;
2672 }
2673
2674out:
2675 wl1271_free_ap_keys(wl);
2676 return ret;
2677}
2678
2679static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2680 u8 key_size, const u8 *key, u32 tx_seq_32,
2681 u16 tx_seq_16, struct ieee80211_sta *sta)
2682{
2683 int ret;
2684 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2685
2686 if (is_ap) {
2687 struct wl1271_station *wl_sta;
2688 u8 hlid;
2689
2690 if (sta) {
2691 wl_sta = (struct wl1271_station *)sta->drv_priv;
2692 hlid = wl_sta->hlid;
2693 } else {
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002694 hlid = wl->ap_bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002695 }
2696
2697 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2698 /*
2699 * We do not support removing keys after AP shutdown.
2700 * Pretend we do to make mac80211 happy.
2701 */
2702 if (action != KEY_ADD_OR_REPLACE)
2703 return 0;
2704
2705 ret = wl1271_record_ap_key(wl, id,
2706 key_type, key_size,
2707 key, hlid, tx_seq_32,
2708 tx_seq_16);
2709 } else {
2710 ret = wl1271_cmd_set_ap_key(wl, action,
2711 id, key_type, key_size,
2712 key, hlid, tx_seq_32,
2713 tx_seq_16);
2714 }
2715
2716 if (ret < 0)
2717 return ret;
2718 } else {
2719 const u8 *addr;
2720 static const u8 bcast_addr[ETH_ALEN] = {
2721 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2722 };
2723
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002724 /*
2725 * A STA set to GEM cipher requires 2 tx spare blocks.
2726 * Return to default value when GEM cipher key is removed
2727 */
2728 if (key_type == KEY_GEM) {
2729 if (action == KEY_ADD_OR_REPLACE)
2730 wl->tx_spare_blocks = 2;
2731 else if (action == KEY_REMOVE)
2732 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2733 }
2734
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002735 addr = sta ? sta->addr : bcast_addr;
2736
2737 if (is_zero_ether_addr(addr)) {
2738 /* We dont support TX only encryption */
2739 return -EOPNOTSUPP;
2740 }
2741
2742 /* The wl1271 does not allow to remove unicast keys - they
2743 will be cleared automatically on next CMD_JOIN. Ignore the
2744 request silently, as we dont want the mac80211 to emit
2745 an error message. */
2746 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2747 return 0;
2748
Eliad Peller010d3d32011-08-14 13:17:31 +03002749 /* don't remove key if hlid was already deleted */
2750 if (action == KEY_REMOVE &&
2751 wl->sta_hlid == WL12XX_INVALID_LINK_ID)
2752 return 0;
2753
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002754 ret = wl1271_cmd_set_sta_key(wl, action,
2755 id, key_type, key_size,
2756 key, addr, tx_seq_32,
2757 tx_seq_16);
2758 if (ret < 0)
2759 return ret;
2760
2761 /* the default WEP key needs to be configured at least once */
2762 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002763 ret = wl12xx_cmd_set_default_wep_key(wl,
2764 wl->default_key,
2765 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002766 if (ret < 0)
2767 return ret;
2768 }
2769 }
2770
2771 return 0;
2772}
2773
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002774static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2775 struct ieee80211_vif *vif,
2776 struct ieee80211_sta *sta,
2777 struct ieee80211_key_conf *key_conf)
2778{
2779 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002780 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002781 u32 tx_seq_32 = 0;
2782 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002783 u8 key_type;
2784
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002785 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2786
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002787 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002788 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002789 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002790 key_conf->keylen, key_conf->flags);
2791 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2792
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002793 mutex_lock(&wl->mutex);
2794
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002795 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2796 ret = -EAGAIN;
2797 goto out_unlock;
2798 }
2799
Ido Yariva6208652011-03-01 15:14:41 +02002800 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002801 if (ret < 0)
2802 goto out_unlock;
2803
Johannes Berg97359d12010-08-10 09:46:38 +02002804 switch (key_conf->cipher) {
2805 case WLAN_CIPHER_SUITE_WEP40:
2806 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002807 key_type = KEY_WEP;
2808
2809 key_conf->hw_key_idx = key_conf->keyidx;
2810 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002811 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002812 key_type = KEY_TKIP;
2813
2814 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002815 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2816 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002817 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002818 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002819 key_type = KEY_AES;
2820
2821 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002822 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2823 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002824 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002825 case WL1271_CIPHER_SUITE_GEM:
2826 key_type = KEY_GEM;
2827 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2828 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2829 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002830 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002831 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002832
2833 ret = -EOPNOTSUPP;
2834 goto out_sleep;
2835 }
2836
2837 switch (cmd) {
2838 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002839 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2840 key_conf->keyidx, key_type,
2841 key_conf->keylen, key_conf->key,
2842 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002843 if (ret < 0) {
2844 wl1271_error("Could not add or replace key");
2845 goto out_sleep;
2846 }
2847 break;
2848
2849 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002850 ret = wl1271_set_key(wl, KEY_REMOVE,
2851 key_conf->keyidx, key_type,
2852 key_conf->keylen, key_conf->key,
2853 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002854 if (ret < 0) {
2855 wl1271_error("Could not remove key");
2856 goto out_sleep;
2857 }
2858 break;
2859
2860 default:
2861 wl1271_error("Unsupported key cmd 0x%x", cmd);
2862 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002863 break;
2864 }
2865
2866out_sleep:
2867 wl1271_ps_elp_sleep(wl);
2868
2869out_unlock:
2870 mutex_unlock(&wl->mutex);
2871
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002872 return ret;
2873}
2874
2875static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002876 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002877 struct cfg80211_scan_request *req)
2878{
2879 struct wl1271 *wl = hw->priv;
2880 int ret;
2881 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002882 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002883
2884 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2885
2886 if (req->n_ssids) {
2887 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002888 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002889 }
2890
2891 mutex_lock(&wl->mutex);
2892
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002893 if (wl->state == WL1271_STATE_OFF) {
2894 /*
2895 * We cannot return -EBUSY here because cfg80211 will expect
2896 * a call to ieee80211_scan_completed if we do - in this case
2897 * there won't be any call.
2898 */
2899 ret = -EAGAIN;
2900 goto out;
2901 }
2902
Ido Yariva6208652011-03-01 15:14:41 +02002903 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002904 if (ret < 0)
2905 goto out;
2906
Eliad Peller251c1772011-08-14 13:17:17 +03002907 /* cancel ROC before scanning */
2908 if (wl12xx_is_roc(wl)) {
2909 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2910 /* don't allow scanning right now */
2911 ret = -EBUSY;
2912 goto out_sleep;
2913 }
2914 wl12xx_croc(wl, wl->dev_role_id);
2915 wl12xx_cmd_role_stop_dev(wl);
2916 }
2917
Eliad Peller784f6942011-10-05 11:55:39 +02002918 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002919out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002920 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002921out:
2922 mutex_unlock(&wl->mutex);
2923
2924 return ret;
2925}
2926
Eliad Peller73ecce32011-06-27 13:06:45 +03002927static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2928 struct ieee80211_vif *vif)
2929{
2930 struct wl1271 *wl = hw->priv;
2931 int ret;
2932
2933 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2934
2935 mutex_lock(&wl->mutex);
2936
2937 if (wl->state == WL1271_STATE_OFF)
2938 goto out;
2939
2940 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2941 goto out;
2942
2943 ret = wl1271_ps_elp_wakeup(wl);
2944 if (ret < 0)
2945 goto out;
2946
2947 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2948 ret = wl1271_scan_stop(wl);
2949 if (ret < 0)
2950 goto out_sleep;
2951 }
2952 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2953 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002954 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03002955 wl->scan.req = NULL;
2956 ieee80211_scan_completed(wl->hw, true);
2957
2958out_sleep:
2959 wl1271_ps_elp_sleep(wl);
2960out:
2961 mutex_unlock(&wl->mutex);
2962
2963 cancel_delayed_work_sync(&wl->scan_complete_work);
2964}
2965
Luciano Coelho33c2c062011-05-10 14:46:02 +03002966static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2967 struct ieee80211_vif *vif,
2968 struct cfg80211_sched_scan_request *req,
2969 struct ieee80211_sched_scan_ies *ies)
2970{
2971 struct wl1271 *wl = hw->priv;
2972 int ret;
2973
2974 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2975
2976 mutex_lock(&wl->mutex);
2977
2978 ret = wl1271_ps_elp_wakeup(wl);
2979 if (ret < 0)
2980 goto out;
2981
2982 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2983 if (ret < 0)
2984 goto out_sleep;
2985
2986 ret = wl1271_scan_sched_scan_start(wl);
2987 if (ret < 0)
2988 goto out_sleep;
2989
2990 wl->sched_scanning = true;
2991
2992out_sleep:
2993 wl1271_ps_elp_sleep(wl);
2994out:
2995 mutex_unlock(&wl->mutex);
2996 return ret;
2997}
2998
2999static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3000 struct ieee80211_vif *vif)
3001{
3002 struct wl1271 *wl = hw->priv;
3003 int ret;
3004
3005 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3006
3007 mutex_lock(&wl->mutex);
3008
3009 ret = wl1271_ps_elp_wakeup(wl);
3010 if (ret < 0)
3011 goto out;
3012
3013 wl1271_scan_sched_scan_stop(wl);
3014
3015 wl1271_ps_elp_sleep(wl);
3016out:
3017 mutex_unlock(&wl->mutex);
3018}
3019
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003020static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3021{
3022 struct wl1271 *wl = hw->priv;
3023 int ret = 0;
3024
3025 mutex_lock(&wl->mutex);
3026
3027 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3028 ret = -EAGAIN;
3029 goto out;
3030 }
3031
Ido Yariva6208652011-03-01 15:14:41 +02003032 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003033 if (ret < 0)
3034 goto out;
3035
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003036 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003037 if (ret < 0)
3038 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3039
3040 wl1271_ps_elp_sleep(wl);
3041
3042out:
3043 mutex_unlock(&wl->mutex);
3044
3045 return ret;
3046}
3047
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003048static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3049{
3050 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003051 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003052
3053 mutex_lock(&wl->mutex);
3054
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003055 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3056 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003057 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003058 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003059
Ido Yariva6208652011-03-01 15:14:41 +02003060 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003061 if (ret < 0)
3062 goto out;
3063
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003064 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003065 if (ret < 0)
3066 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
3067
3068 wl1271_ps_elp_sleep(wl);
3069
3070out:
3071 mutex_unlock(&wl->mutex);
3072
3073 return ret;
3074}
3075
Arik Nemtsove78a2872010-10-16 19:07:21 +02003076static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003077 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003078{
Eliad Peller889cb362011-05-01 09:56:45 +03003079 u8 ssid_len;
3080 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3081 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003082
Eliad Peller889cb362011-05-01 09:56:45 +03003083 if (!ptr) {
3084 wl1271_error("No SSID in IEs!");
3085 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003086 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003087
Eliad Peller889cb362011-05-01 09:56:45 +03003088 ssid_len = ptr[1];
3089 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3090 wl1271_error("SSID is too long!");
3091 return -EINVAL;
3092 }
3093
3094 wl->ssid_len = ssid_len;
3095 memcpy(wl->ssid, ptr+2, ssid_len);
3096 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003097}
3098
Eliad Pellerd48055d2011-09-15 12:07:04 +03003099static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3100{
3101 int len;
3102 const u8 *next, *end = skb->data + skb->len;
3103 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3104 skb->len - ieoffset);
3105 if (!ie)
3106 return;
3107 len = ie[1] + 2;
3108 next = ie + len;
3109 memmove(ie, next, end - next);
3110 skb_trim(skb, skb->len - len);
3111}
3112
Eliad Peller26b4bf22011-09-15 12:07:05 +03003113static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3114 unsigned int oui, u8 oui_type,
3115 int ieoffset)
3116{
3117 int len;
3118 const u8 *next, *end = skb->data + skb->len;
3119 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3120 skb->data + ieoffset,
3121 skb->len - ieoffset);
3122 if (!ie)
3123 return;
3124 len = ie[1] + 2;
3125 next = ie + len;
3126 memmove(ie, next, end - next);
3127 skb_trim(skb, skb->len - len);
3128}
3129
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003130static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
3131 u8 *probe_rsp_data,
3132 size_t probe_rsp_len,
3133 u32 rates)
3134{
3135 struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
3136 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3137 int ssid_ie_offset, ie_offset, templ_len;
3138 const u8 *ptr;
3139
3140 /* no need to change probe response if the SSID is set correctly */
3141 if (wl->ssid_len > 0)
3142 return wl1271_cmd_template_set(wl,
3143 CMD_TEMPL_AP_PROBE_RESPONSE,
3144 probe_rsp_data,
3145 probe_rsp_len, 0,
3146 rates);
3147
3148 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3149 wl1271_error("probe_rsp template too big");
3150 return -EINVAL;
3151 }
3152
3153 /* start searching from IE offset */
3154 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3155
3156 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3157 probe_rsp_len - ie_offset);
3158 if (!ptr) {
3159 wl1271_error("No SSID in beacon!");
3160 return -EINVAL;
3161 }
3162
3163 ssid_ie_offset = ptr - probe_rsp_data;
3164 ptr += (ptr[1] + 2);
3165
3166 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3167
3168 /* insert SSID from bss_conf */
3169 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3170 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3171 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3172 bss_conf->ssid, bss_conf->ssid_len);
3173 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3174
3175 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3176 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3177 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3178
3179 return wl1271_cmd_template_set(wl,
3180 CMD_TEMPL_AP_PROBE_RESPONSE,
3181 probe_rsp_templ,
3182 templ_len, 0,
3183 rates);
3184}
3185
Arik Nemtsove78a2872010-10-16 19:07:21 +02003186static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
3187 struct ieee80211_bss_conf *bss_conf,
3188 u32 changed)
3189{
3190 int ret = 0;
3191
3192 if (changed & BSS_CHANGED_ERP_SLOT) {
3193 if (bss_conf->use_short_slot)
3194 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
3195 else
3196 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
3197 if (ret < 0) {
3198 wl1271_warning("Set slot time failed %d", ret);
3199 goto out;
3200 }
3201 }
3202
3203 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3204 if (bss_conf->use_short_preamble)
3205 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
3206 else
3207 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
3208 }
3209
3210 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3211 if (bss_conf->use_cts_prot)
3212 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
3213 else
3214 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
3215 if (ret < 0) {
3216 wl1271_warning("Set ctsprotect failed %d", ret);
3217 goto out;
3218 }
3219 }
3220
3221out:
3222 return ret;
3223}
3224
3225static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3226 struct ieee80211_vif *vif,
3227 struct ieee80211_bss_conf *bss_conf,
3228 u32 changed)
3229{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003230 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003231 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3232 int ret = 0;
3233
3234 if ((changed & BSS_CHANGED_BEACON_INT)) {
3235 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3236 bss_conf->beacon_int);
3237
3238 wl->beacon_int = bss_conf->beacon_int;
3239 }
3240
3241 if ((changed & BSS_CHANGED_BEACON)) {
3242 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003243 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003244 int ieoffset = offsetof(struct ieee80211_mgmt,
3245 u.beacon.variable);
3246 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3247 u16 tmpl_id;
3248
3249 if (!beacon)
3250 goto out;
3251
3252 wl1271_debug(DEBUG_MASTER, "beacon updated");
3253
3254 ret = wl1271_ssid_set(wl, beacon, ieoffset);
3255 if (ret < 0) {
3256 dev_kfree_skb(beacon);
3257 goto out;
3258 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003259 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003260 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3261 CMD_TEMPL_BEACON;
3262 ret = wl1271_cmd_template_set(wl, tmpl_id,
3263 beacon->data,
3264 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003265 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003266 if (ret < 0) {
3267 dev_kfree_skb(beacon);
3268 goto out;
3269 }
3270
Eliad Pellerd48055d2011-09-15 12:07:04 +03003271 /* remove TIM ie from probe response */
3272 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3273
Eliad Peller26b4bf22011-09-15 12:07:05 +03003274 /*
3275 * remove p2p ie from probe response.
3276 * the fw reponds to probe requests that don't include
3277 * the p2p ie. probe requests with p2p ie will be passed,
3278 * and will be responded by the supplicant (the spec
3279 * forbids including the p2p ie when responding to probe
3280 * requests that didn't include it).
3281 */
3282 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3283 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3284
Arik Nemtsove78a2872010-10-16 19:07:21 +02003285 hdr = (struct ieee80211_hdr *) beacon->data;
3286 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3287 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003288 if (is_ap)
3289 ret = wl1271_ap_set_probe_resp_tmpl(wl,
3290 beacon->data,
3291 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003292 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003293 else
3294 ret = wl1271_cmd_template_set(wl,
3295 CMD_TEMPL_PROBE_RESPONSE,
3296 beacon->data,
3297 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003298 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003299 dev_kfree_skb(beacon);
3300 if (ret < 0)
3301 goto out;
3302 }
3303
3304out:
3305 return ret;
3306}
3307
3308/* AP mode changes */
3309static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003310 struct ieee80211_vif *vif,
3311 struct ieee80211_bss_conf *bss_conf,
3312 u32 changed)
3313{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003314 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003315 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003316
Arik Nemtsove78a2872010-10-16 19:07:21 +02003317 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3318 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003319
Eliad Peller87fbcb02011-10-05 11:55:41 +02003320 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003321 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003322 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003323 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003324
Eliad Peller87fbcb02011-10-05 11:55:41 +02003325 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003326 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003327 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003328 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003329 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003330
Eliad Peller784f6942011-10-05 11:55:39 +02003331 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003332 if (ret < 0)
3333 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003334 }
3335
Arik Nemtsove78a2872010-10-16 19:07:21 +02003336 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3337 if (ret < 0)
3338 goto out;
3339
3340 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3341 if (bss_conf->enable_beacon) {
3342 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003343 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003344 if (ret < 0)
3345 goto out;
3346
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003347 ret = wl1271_ap_init_hwenc(wl);
3348 if (ret < 0)
3349 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003350
3351 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3352 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003353 }
3354 } else {
3355 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003356 ret = wl12xx_cmd_role_stop_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003357 if (ret < 0)
3358 goto out;
3359
3360 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3361 wl1271_debug(DEBUG_AP, "stopped AP");
3362 }
3363 }
3364 }
3365
3366 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3367 if (ret < 0)
3368 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003369
3370 /* Handle HT information change */
3371 if ((changed & BSS_CHANGED_HT) &&
3372 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3373 ret = wl1271_acx_set_ht_information(wl,
3374 bss_conf->ht_operation_mode);
3375 if (ret < 0) {
3376 wl1271_warning("Set ht information failed %d", ret);
3377 goto out;
3378 }
3379 }
3380
Arik Nemtsove78a2872010-10-16 19:07:21 +02003381out:
3382 return;
3383}
3384
3385/* STA/IBSS mode changes */
3386static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3387 struct ieee80211_vif *vif,
3388 struct ieee80211_bss_conf *bss_conf,
3389 u32 changed)
3390{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003391 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003392 bool do_join = false, set_assoc = false;
3393 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003394 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003395 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003396 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003397 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003398 bool sta_exists = false;
3399 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003400
3401 if (is_ibss) {
3402 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3403 changed);
3404 if (ret < 0)
3405 goto out;
3406 }
3407
Eliad Peller227e81e2011-08-14 13:17:26 +03003408 if (changed & BSS_CHANGED_IBSS) {
3409 if (bss_conf->ibss_joined) {
3410 set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
3411 ibss_joined = true;
3412 } else {
3413 if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
3414 &wl->flags)) {
3415 wl1271_unjoin(wl);
3416 wl12xx_cmd_role_start_dev(wl);
3417 wl12xx_roc(wl, wl->dev_role_id);
3418 }
3419 }
3420 }
3421
3422 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003423 do_join = true;
3424
3425 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003426 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003427 do_join = true;
3428
Eliad Peller227e81e2011-08-14 13:17:26 +03003429 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003430 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3431 bss_conf->enable_beacon ? "enabled" : "disabled");
3432
3433 if (bss_conf->enable_beacon)
3434 wl->set_bss_type = BSS_TYPE_IBSS;
3435 else
3436 wl->set_bss_type = BSS_TYPE_STA_BSS;
3437 do_join = true;
3438 }
3439
Arik Nemtsove78a2872010-10-16 19:07:21 +02003440 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003441 bool enable = false;
3442 if (bss_conf->cqm_rssi_thold)
3443 enable = true;
3444 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3445 bss_conf->cqm_rssi_thold,
3446 bss_conf->cqm_rssi_hyst);
3447 if (ret < 0)
3448 goto out;
3449 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3450 }
3451
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003452 if ((changed & BSS_CHANGED_BSSID) &&
3453 /*
3454 * Now we know the correct bssid, so we send a new join command
3455 * and enable the BSSID filter
3456 */
3457 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003458 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003459
Eliad Pellerfa287b82010-12-26 09:27:50 +01003460 if (!is_zero_ether_addr(wl->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003461 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003462 if (ret < 0)
3463 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003464
Eliad Peller784f6942011-10-05 11:55:39 +02003465 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003466 if (ret < 0)
3467 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003468
Eliad Pellerfa287b82010-12-26 09:27:50 +01003469 /* Need to update the BSSID (for filtering etc) */
3470 do_join = true;
3471 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003472 }
3473
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003474 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3475 rcu_read_lock();
3476 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3477 if (!sta)
3478 goto sta_not_found;
3479
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003480 /* save the supp_rates of the ap */
3481 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3482 if (sta->ht_cap.ht_supported)
3483 sta_rate_set |=
3484 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003485 sta_ht_cap = sta->ht_cap;
3486 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003487
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003488sta_not_found:
3489 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003490 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003491
Arik Nemtsove78a2872010-10-16 19:07:21 +02003492 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003493 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003494 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003495 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003496 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003497 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003498
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003499 wl->ps_poll_failures = 0;
3500
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003501 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003502 * use basic rates from AP, and determine lowest rate
3503 * to use with control frames.
3504 */
3505 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003506 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003507 wl1271_tx_enabled_rates_get(wl, rates,
3508 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003509 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003510 wl1271_tx_min_rate_get(wl,
3511 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003512 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003513 wlvif->rate_set =
3514 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003515 sta_rate_set,
3516 wl->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003517 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003518 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003519 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003520
3521 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003522 * with wl1271, we don't need to update the
3523 * beacon_int and dtim_period, because the firmware
3524 * updates it by itself when the first beacon is
3525 * received after a join.
3526 */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003527 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wl->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003528 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003529 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003530
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003531 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003532 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003533 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003534 dev_kfree_skb(wl->probereq);
3535 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3536 ieoffset = offsetof(struct ieee80211_mgmt,
3537 u.probe_req.variable);
3538 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003539
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003540 /* enable the connection monitoring feature */
3541 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003542 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003543 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003544 } else {
3545 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003546 bool was_assoc =
3547 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3548 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003549 bool was_ifup =
3550 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3551 &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003552 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003553
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003554 /* free probe-request template */
3555 dev_kfree_skb(wl->probereq);
3556 wl->probereq = NULL;
3557
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003558 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003559 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003560
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003561 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003562 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003563 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003564 wl1271_tx_min_rate_get(wl,
3565 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003566 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003567 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003568 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003569
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003570 /* disable connection monitor features */
3571 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003572
3573 /* Disable the keep-alive feature */
3574 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003575 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003576 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003577
3578 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003579 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003580 u32 conf_flags = wl->hw->conf.flags;
3581 /*
3582 * we might have to disable roc, if there was
3583 * no IF_OPER_UP notification.
3584 */
3585 if (!was_ifup) {
3586 ret = wl12xx_croc(wl, wl->role_id);
3587 if (ret < 0)
3588 goto out;
3589 }
3590 /*
3591 * (we also need to disable roc in case of
3592 * roaming on the same channel. until we will
3593 * have a better flow...)
3594 */
3595 if (test_bit(wl->dev_role_id, wl->roc_map)) {
3596 ret = wl12xx_croc(wl, wl->dev_role_id);
3597 if (ret < 0)
3598 goto out;
3599 }
3600
Eliad Peller30df14d2011-04-05 19:13:28 +03003601 wl1271_unjoin(wl);
Eliad Peller251c1772011-08-14 13:17:17 +03003602 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
3603 wl12xx_cmd_role_start_dev(wl);
3604 wl12xx_roc(wl, wl->dev_role_id);
3605 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003606 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003607 }
3608 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003609
Eliad Pellerd192d262011-05-24 14:33:08 +03003610 if (changed & BSS_CHANGED_IBSS) {
3611 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3612 bss_conf->ibss_joined);
3613
3614 if (bss_conf->ibss_joined) {
3615 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003616 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003617 wl1271_tx_enabled_rates_get(wl, rates,
3618 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003619 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003620 wl1271_tx_min_rate_get(wl,
3621 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003622
Shahar Levi06b660e2011-09-05 13:54:36 +03003623 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003624 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3625 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003626 if (ret < 0)
3627 goto out;
3628 }
3629 }
3630
Arik Nemtsove78a2872010-10-16 19:07:21 +02003631 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3632 if (ret < 0)
3633 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003634
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003635 if (changed & BSS_CHANGED_ARP_FILTER) {
3636 __be32 addr = bss_conf->arp_addr_list[0];
3637 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3638
Eliad Pellerc5312772010-12-09 11:31:27 +02003639 if (bss_conf->arp_addr_cnt == 1 &&
3640 bss_conf->arp_filter_enabled) {
3641 /*
3642 * The template should have been configured only upon
3643 * association. however, it seems that the correct ip
3644 * isn't being set (when sending), so we have to
3645 * reconfigure the template upon every ip change.
3646 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003647 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003648 if (ret < 0) {
3649 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003650 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003651 }
3652
3653 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003654 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003655 addr);
3656 } else
3657 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003658
3659 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003660 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003661 }
3662
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003663 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003664 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003665 if (ret < 0) {
3666 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003667 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003668 }
Eliad Peller251c1772011-08-14 13:17:17 +03003669
3670 /* ROC until connected (after EAPOL exchange) */
3671 if (!is_ibss) {
3672 ret = wl12xx_roc(wl, wl->role_id);
3673 if (ret < 0)
3674 goto out;
3675
3676 wl1271_check_operstate(wl,
3677 ieee80211_get_operstate(vif));
3678 }
3679 /*
3680 * stop device role if started (we might already be in
3681 * STA role). TODO: make it better.
3682 */
3683 if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3684 ret = wl12xx_croc(wl, wl->dev_role_id);
3685 if (ret < 0)
3686 goto out;
3687
3688 ret = wl12xx_cmd_role_stop_dev(wl);
3689 if (ret < 0)
3690 goto out;
3691 }
Eliad Peller05dba352011-08-23 16:37:01 +03003692
3693 /* If we want to go in PSM but we're not there yet */
3694 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3695 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
3696 enum wl1271_cmd_ps_mode mode;
3697
3698 mode = STATION_POWER_SAVE_MODE;
3699 ret = wl1271_ps_set_mode(wl, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003700 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003701 true);
3702 if (ret < 0)
3703 goto out;
3704 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003705 }
3706
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003707 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003708 if (sta_exists) {
3709 if ((changed & BSS_CHANGED_HT) &&
3710 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003711 ret = wl1271_acx_set_ht_capabilities(wl,
3712 &sta_ht_cap,
3713 true,
3714 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003715 if (ret < 0) {
3716 wl1271_warning("Set ht cap true failed %d",
3717 ret);
3718 goto out;
3719 }
3720 }
3721 /* handle new association without HT and disassociation */
3722 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003723 ret = wl1271_acx_set_ht_capabilities(wl,
3724 &sta_ht_cap,
3725 false,
3726 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003727 if (ret < 0) {
3728 wl1271_warning("Set ht cap false failed %d",
3729 ret);
3730 goto out;
3731 }
3732 }
3733 }
3734
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003735 /* Handle HT information change. Done after join. */
3736 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003737 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3738 ret = wl1271_acx_set_ht_information(wl,
3739 bss_conf->ht_operation_mode);
3740 if (ret < 0) {
3741 wl1271_warning("Set ht information failed %d", ret);
3742 goto out;
3743 }
3744 }
3745
Arik Nemtsove78a2872010-10-16 19:07:21 +02003746out:
3747 return;
3748}
3749
3750static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3751 struct ieee80211_vif *vif,
3752 struct ieee80211_bss_conf *bss_conf,
3753 u32 changed)
3754{
3755 struct wl1271 *wl = hw->priv;
3756 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3757 int ret;
3758
3759 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3760 (int)changed);
3761
3762 mutex_lock(&wl->mutex);
3763
3764 if (unlikely(wl->state == WL1271_STATE_OFF))
3765 goto out;
3766
Ido Yariva6208652011-03-01 15:14:41 +02003767 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003768 if (ret < 0)
3769 goto out;
3770
3771 if (is_ap)
3772 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3773 else
3774 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3775
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003776 wl1271_ps_elp_sleep(wl);
3777
3778out:
3779 mutex_unlock(&wl->mutex);
3780}
3781
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003782static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3783 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003784 const struct ieee80211_tx_queue_params *params)
3785{
3786 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003787 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003788 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003789
3790 mutex_lock(&wl->mutex);
3791
3792 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3793
Kalle Valo4695dc92010-03-18 12:26:38 +02003794 if (params->uapsd)
3795 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3796 else
3797 ps_scheme = CONF_PS_SCHEME_LEGACY;
3798
Arik Nemtsov488fc542010-10-16 20:33:45 +02003799 if (wl->state == WL1271_STATE_OFF) {
3800 /*
3801 * If the state is off, the parameters will be recorded and
3802 * configured on init. This happens in AP-mode.
3803 */
3804 struct conf_tx_ac_category *conf_ac =
3805 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3806 struct conf_tx_tid *conf_tid =
3807 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3808
3809 conf_ac->ac = wl1271_tx_get_queue(queue);
3810 conf_ac->cw_min = (u8)params->cw_min;
3811 conf_ac->cw_max = params->cw_max;
3812 conf_ac->aifsn = params->aifs;
3813 conf_ac->tx_op_limit = params->txop << 5;
3814
3815 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3816 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3817 conf_tid->tsid = wl1271_tx_get_queue(queue);
3818 conf_tid->ps_scheme = ps_scheme;
3819 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3820 conf_tid->apsd_conf[0] = 0;
3821 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003822 goto out;
3823 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003824
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003825 ret = wl1271_ps_elp_wakeup(wl);
3826 if (ret < 0)
3827 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003828
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003829 /*
3830 * the txop is confed in units of 32us by the mac80211,
3831 * we need us
3832 */
3833 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3834 params->cw_min, params->cw_max,
3835 params->aifs, params->txop << 5);
3836 if (ret < 0)
3837 goto out_sleep;
3838
3839 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3840 CONF_CHANNEL_TYPE_EDCF,
3841 wl1271_tx_get_queue(queue),
3842 ps_scheme, CONF_ACK_POLICY_LEGACY,
3843 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003844
3845out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003846 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003847
3848out:
3849 mutex_unlock(&wl->mutex);
3850
3851 return ret;
3852}
3853
Eliad Peller37a41b42011-09-21 14:06:11 +03003854static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
3855 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003856{
3857
3858 struct wl1271 *wl = hw->priv;
3859 u64 mactime = ULLONG_MAX;
3860 int ret;
3861
3862 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3863
3864 mutex_lock(&wl->mutex);
3865
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003866 if (unlikely(wl->state == WL1271_STATE_OFF))
3867 goto out;
3868
Ido Yariva6208652011-03-01 15:14:41 +02003869 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003870 if (ret < 0)
3871 goto out;
3872
3873 ret = wl1271_acx_tsf_info(wl, &mactime);
3874 if (ret < 0)
3875 goto out_sleep;
3876
3877out_sleep:
3878 wl1271_ps_elp_sleep(wl);
3879
3880out:
3881 mutex_unlock(&wl->mutex);
3882 return mactime;
3883}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003884
John W. Linvilleece550d2010-07-28 16:41:06 -04003885static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3886 struct survey_info *survey)
3887{
3888 struct wl1271 *wl = hw->priv;
3889 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003890
John W. Linvilleece550d2010-07-28 16:41:06 -04003891 if (idx != 0)
3892 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003893
John W. Linvilleece550d2010-07-28 16:41:06 -04003894 survey->channel = conf->channel;
3895 survey->filled = SURVEY_INFO_NOISE_DBM;
3896 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003897
John W. Linvilleece550d2010-07-28 16:41:06 -04003898 return 0;
3899}
3900
Arik Nemtsov409622e2011-02-23 00:22:29 +02003901static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003902 struct ieee80211_sta *sta,
3903 u8 *hlid)
3904{
3905 struct wl1271_station *wl_sta;
3906 int id;
3907
3908 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3909 if (id >= AP_MAX_STATIONS) {
3910 wl1271_warning("could not allocate HLID - too much stations");
3911 return -EBUSY;
3912 }
3913
3914 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsov04216da2011-08-14 13:17:38 +03003915 set_bit(id, wl->ap_hlid_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003916 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3917 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003918 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03003919 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003920 return 0;
3921}
3922
Arik Nemtsovf1acea92011-08-25 12:43:17 +03003923void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003924{
3925 int id = hlid - WL1271_AP_STA_HLID_START;
3926
Arik Nemtsovf1acea92011-08-25 12:43:17 +03003927 if (hlid < WL1271_AP_STA_HLID_START)
3928 return;
3929
3930 if (!test_bit(id, wl->ap_hlid_map))
Arik Nemtsov409622e2011-02-23 00:22:29 +02003931 return;
3932
Arik Nemtsov04216da2011-08-14 13:17:38 +03003933 clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003934 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003935 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003936 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003937 __clear_bit(hlid, &wl->ap_ps_map);
3938 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +03003939 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003940}
3941
3942static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3943 struct ieee80211_vif *vif,
3944 struct ieee80211_sta *sta)
3945{
3946 struct wl1271 *wl = hw->priv;
3947 int ret = 0;
3948 u8 hlid;
3949
3950 mutex_lock(&wl->mutex);
3951
3952 if (unlikely(wl->state == WL1271_STATE_OFF))
3953 goto out;
3954
3955 if (wl->bss_type != BSS_TYPE_AP_BSS)
3956 goto out;
3957
3958 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3959
Arik Nemtsov409622e2011-02-23 00:22:29 +02003960 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003961 if (ret < 0)
3962 goto out;
3963
Ido Yariva6208652011-03-01 15:14:41 +02003964 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003965 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003966 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003967
Eliad Pellerc690ec82011-08-14 13:17:07 +03003968 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003969 if (ret < 0)
3970 goto out_sleep;
3971
Eliad Pellerb67476e2011-08-14 13:17:23 +03003972 ret = wl12xx_cmd_set_peer_state(wl, hlid);
3973 if (ret < 0)
3974 goto out_sleep;
3975
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003976 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
3977 if (ret < 0)
3978 goto out_sleep;
3979
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003980out_sleep:
3981 wl1271_ps_elp_sleep(wl);
3982
Arik Nemtsov409622e2011-02-23 00:22:29 +02003983out_free_sta:
3984 if (ret < 0)
3985 wl1271_free_sta(wl, hlid);
3986
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003987out:
3988 mutex_unlock(&wl->mutex);
3989 return ret;
3990}
3991
3992static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3993 struct ieee80211_vif *vif,
3994 struct ieee80211_sta *sta)
3995{
3996 struct wl1271 *wl = hw->priv;
3997 struct wl1271_station *wl_sta;
3998 int ret = 0, id;
3999
4000 mutex_lock(&wl->mutex);
4001
4002 if (unlikely(wl->state == WL1271_STATE_OFF))
4003 goto out;
4004
4005 if (wl->bss_type != BSS_TYPE_AP_BSS)
4006 goto out;
4007
4008 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4009
4010 wl_sta = (struct wl1271_station *)sta->drv_priv;
4011 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
4012 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
4013 goto out;
4014
Ido Yariva6208652011-03-01 15:14:41 +02004015 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004016 if (ret < 0)
4017 goto out;
4018
Eliad Pellerc690ec82011-08-14 13:17:07 +03004019 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004020 if (ret < 0)
4021 goto out_sleep;
4022
Arik Nemtsov409622e2011-02-23 00:22:29 +02004023 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004024
4025out_sleep:
4026 wl1271_ps_elp_sleep(wl);
4027
4028out:
4029 mutex_unlock(&wl->mutex);
4030 return ret;
4031}
4032
Luciano Coelho4623ec72011-03-21 19:26:41 +02004033static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4034 struct ieee80211_vif *vif,
4035 enum ieee80211_ampdu_mlme_action action,
4036 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4037 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004038{
4039 struct wl1271 *wl = hw->priv;
4040 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004041 u8 hlid, *ba_bitmap;
4042
4043 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4044 tid);
4045
4046 /* sanity check - the fields in FW are only 8bits wide */
4047 if (WARN_ON(tid > 0xFF))
4048 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004049
4050 mutex_lock(&wl->mutex);
4051
4052 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4053 ret = -EAGAIN;
4054 goto out;
4055 }
4056
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004057 if (wl->bss_type == BSS_TYPE_STA_BSS) {
4058 hlid = wl->sta_hlid;
4059 ba_bitmap = &wl->ba_rx_bitmap;
4060 } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
4061 struct wl1271_station *wl_sta;
4062
4063 wl_sta = (struct wl1271_station *)sta->drv_priv;
4064 hlid = wl_sta->hlid;
4065 ba_bitmap = &wl->links[hlid].ba_bitmap;
4066 } else {
4067 ret = -EINVAL;
4068 goto out;
4069 }
4070
Ido Yariva6208652011-03-01 15:14:41 +02004071 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004072 if (ret < 0)
4073 goto out;
4074
Shahar Levi70559a02011-05-22 16:10:22 +03004075 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4076 tid, action);
4077
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004078 switch (action) {
4079 case IEEE80211_AMPDU_RX_START:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004080 if (!wl->ba_support || !wl->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004081 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004082 break;
4083 }
4084
4085 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4086 ret = -EBUSY;
4087 wl1271_error("exceeded max RX BA sessions");
4088 break;
4089 }
4090
4091 if (*ba_bitmap & BIT(tid)) {
4092 ret = -EINVAL;
4093 wl1271_error("cannot enable RX BA session on active "
4094 "tid: %d", tid);
4095 break;
4096 }
4097
4098 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4099 hlid);
4100 if (!ret) {
4101 *ba_bitmap |= BIT(tid);
4102 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004103 }
4104 break;
4105
4106 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004107 if (!(*ba_bitmap & BIT(tid))) {
4108 ret = -EINVAL;
4109 wl1271_error("no active RX BA session on tid: %d",
4110 tid);
4111 break;
4112 }
4113
4114 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4115 hlid);
4116 if (!ret) {
4117 *ba_bitmap &= ~BIT(tid);
4118 wl->ba_rx_session_count--;
4119 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004120 break;
4121
4122 /*
4123 * The BA initiator session management in FW independently.
4124 * Falling break here on purpose for all TX APDU commands.
4125 */
4126 case IEEE80211_AMPDU_TX_START:
4127 case IEEE80211_AMPDU_TX_STOP:
4128 case IEEE80211_AMPDU_TX_OPERATIONAL:
4129 ret = -EINVAL;
4130 break;
4131
4132 default:
4133 wl1271_error("Incorrect ampdu action id=%x\n", action);
4134 ret = -EINVAL;
4135 }
4136
4137 wl1271_ps_elp_sleep(wl);
4138
4139out:
4140 mutex_unlock(&wl->mutex);
4141
4142 return ret;
4143}
4144
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004145static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4146 struct ieee80211_vif *vif,
4147 const struct cfg80211_bitrate_mask *mask)
4148{
4149 struct wl1271 *wl = hw->priv;
4150 int i;
4151
4152 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4153 mask->control[NL80211_BAND_2GHZ].legacy,
4154 mask->control[NL80211_BAND_5GHZ].legacy);
4155
4156 mutex_lock(&wl->mutex);
4157
4158 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
4159 wl->bitrate_masks[i] =
4160 wl1271_tx_enabled_rates_get(wl,
4161 mask->control[i].legacy,
4162 i);
4163 mutex_unlock(&wl->mutex);
4164
4165 return 0;
4166}
4167
Shahar Levi6d158ff2011-09-08 13:01:33 +03004168static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4169 struct ieee80211_channel_switch *ch_switch)
4170{
4171 struct wl1271 *wl = hw->priv;
4172 int ret;
4173
4174 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4175
4176 mutex_lock(&wl->mutex);
4177
4178 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4179 mutex_unlock(&wl->mutex);
4180 ieee80211_chswitch_done(wl->vif, false);
4181 return;
4182 }
4183
4184 ret = wl1271_ps_elp_wakeup(wl);
4185 if (ret < 0)
4186 goto out;
4187
4188 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
4189
4190 if (!ret)
4191 set_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags);
4192
4193 wl1271_ps_elp_sleep(wl);
4194
4195out:
4196 mutex_unlock(&wl->mutex);
4197}
4198
Arik Nemtsov33437892011-04-26 23:35:39 +03004199static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4200{
4201 struct wl1271 *wl = hw->priv;
4202 bool ret = false;
4203
4204 mutex_lock(&wl->mutex);
4205
4206 if (unlikely(wl->state == WL1271_STATE_OFF))
4207 goto out;
4208
4209 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004210 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004211
4212 /* the above is appropriate for STA mode for PS purposes */
4213 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
4214
4215out:
4216 mutex_unlock(&wl->mutex);
4217
4218 return ret;
4219}
4220
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004221/* can't be const, mac80211 writes to this */
4222static struct ieee80211_rate wl1271_rates[] = {
4223 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004224 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4225 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004226 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004227 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4228 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004229 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4230 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004231 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4232 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004233 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4234 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004235 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4236 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004237 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4238 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004239 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4240 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004241 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004242 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4243 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004244 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004245 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4246 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004247 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004248 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4249 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004250 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004251 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4252 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004253 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004254 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4255 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004256 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004257 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4258 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004259 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004260 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4261 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004262};
4263
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004264/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004265static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004266 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004267 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004268 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4269 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4270 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004271 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004272 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4273 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4274 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004275 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004276 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4277 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4278 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004279 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004280};
4281
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004282/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004283static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004284 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004285 7, /* CONF_HW_RXTX_RATE_MCS7 */
4286 6, /* CONF_HW_RXTX_RATE_MCS6 */
4287 5, /* CONF_HW_RXTX_RATE_MCS5 */
4288 4, /* CONF_HW_RXTX_RATE_MCS4 */
4289 3, /* CONF_HW_RXTX_RATE_MCS3 */
4290 2, /* CONF_HW_RXTX_RATE_MCS2 */
4291 1, /* CONF_HW_RXTX_RATE_MCS1 */
4292 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004293
4294 11, /* CONF_HW_RXTX_RATE_54 */
4295 10, /* CONF_HW_RXTX_RATE_48 */
4296 9, /* CONF_HW_RXTX_RATE_36 */
4297 8, /* CONF_HW_RXTX_RATE_24 */
4298
4299 /* TI-specific rate */
4300 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4301
4302 7, /* CONF_HW_RXTX_RATE_18 */
4303 6, /* CONF_HW_RXTX_RATE_12 */
4304 3, /* CONF_HW_RXTX_RATE_11 */
4305 5, /* CONF_HW_RXTX_RATE_9 */
4306 4, /* CONF_HW_RXTX_RATE_6 */
4307 2, /* CONF_HW_RXTX_RATE_5_5 */
4308 1, /* CONF_HW_RXTX_RATE_2 */
4309 0 /* CONF_HW_RXTX_RATE_1 */
4310};
4311
Shahar Levie8b03a22010-10-13 16:09:39 +02004312/* 11n STA capabilities */
4313#define HW_RX_HIGHEST_RATE 72
4314
Shahar Levi00d20102010-11-08 11:20:10 +00004315#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004316 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4317 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004318 .ht_supported = true, \
4319 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4320 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4321 .mcs = { \
4322 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4323 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4324 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4325 }, \
4326}
4327
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004328/* can't be const, mac80211 writes to this */
4329static struct ieee80211_supported_band wl1271_band_2ghz = {
4330 .channels = wl1271_channels,
4331 .n_channels = ARRAY_SIZE(wl1271_channels),
4332 .bitrates = wl1271_rates,
4333 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004334 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004335};
4336
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004337/* 5 GHz data rates for WL1273 */
4338static struct ieee80211_rate wl1271_rates_5ghz[] = {
4339 { .bitrate = 60,
4340 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4341 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4342 { .bitrate = 90,
4343 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4344 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4345 { .bitrate = 120,
4346 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4347 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4348 { .bitrate = 180,
4349 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4350 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4351 { .bitrate = 240,
4352 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4353 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4354 { .bitrate = 360,
4355 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4356 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4357 { .bitrate = 480,
4358 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4359 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4360 { .bitrate = 540,
4361 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4362 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4363};
4364
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004365/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004366static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004367 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4368 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4369 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4370 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4371 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4372 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4373 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4374 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4375 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4376 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4377 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4378 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4379 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4380 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4381 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4382 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4383 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4384 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4385 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4386 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4387 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4388 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4389 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4390 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4391 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4392 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4393 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4394 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4395 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4396 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4397 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4398 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4399 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4400 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004401};
4402
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004403/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004404static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004405 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004406 7, /* CONF_HW_RXTX_RATE_MCS7 */
4407 6, /* CONF_HW_RXTX_RATE_MCS6 */
4408 5, /* CONF_HW_RXTX_RATE_MCS5 */
4409 4, /* CONF_HW_RXTX_RATE_MCS4 */
4410 3, /* CONF_HW_RXTX_RATE_MCS3 */
4411 2, /* CONF_HW_RXTX_RATE_MCS2 */
4412 1, /* CONF_HW_RXTX_RATE_MCS1 */
4413 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004414
4415 7, /* CONF_HW_RXTX_RATE_54 */
4416 6, /* CONF_HW_RXTX_RATE_48 */
4417 5, /* CONF_HW_RXTX_RATE_36 */
4418 4, /* CONF_HW_RXTX_RATE_24 */
4419
4420 /* TI-specific rate */
4421 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4422
4423 3, /* CONF_HW_RXTX_RATE_18 */
4424 2, /* CONF_HW_RXTX_RATE_12 */
4425 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4426 1, /* CONF_HW_RXTX_RATE_9 */
4427 0, /* CONF_HW_RXTX_RATE_6 */
4428 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4429 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4430 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4431};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004432
4433static struct ieee80211_supported_band wl1271_band_5ghz = {
4434 .channels = wl1271_channels_5ghz,
4435 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4436 .bitrates = wl1271_rates_5ghz,
4437 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004438 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004439};
4440
Tobias Klausera0ea9492010-05-20 10:38:11 +02004441static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004442 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4443 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4444};
4445
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004446static const struct ieee80211_ops wl1271_ops = {
4447 .start = wl1271_op_start,
4448 .stop = wl1271_op_stop,
4449 .add_interface = wl1271_op_add_interface,
4450 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004451#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004452 .suspend = wl1271_op_suspend,
4453 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004454#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004455 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004456 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004457 .configure_filter = wl1271_op_configure_filter,
4458 .tx = wl1271_op_tx,
4459 .set_key = wl1271_op_set_key,
4460 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004461 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004462 .sched_scan_start = wl1271_op_sched_scan_start,
4463 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004464 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004465 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004466 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004467 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004468 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004469 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004470 .sta_add = wl1271_op_sta_add,
4471 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004472 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004473 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004474 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004475 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004476 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004477};
4478
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004479
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004480u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004481{
4482 u8 idx;
4483
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004484 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004485
4486 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4487 wl1271_error("Illegal RX rate from HW: %d", rate);
4488 return 0;
4489 }
4490
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004491 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004492 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4493 wl1271_error("Unsupported RX rate from HW: %d", rate);
4494 return 0;
4495 }
4496
4497 return idx;
4498}
4499
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004500static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4501 struct device_attribute *attr,
4502 char *buf)
4503{
4504 struct wl1271 *wl = dev_get_drvdata(dev);
4505 ssize_t len;
4506
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004507 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004508
4509 mutex_lock(&wl->mutex);
4510 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4511 wl->sg_enabled);
4512 mutex_unlock(&wl->mutex);
4513
4514 return len;
4515
4516}
4517
4518static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4519 struct device_attribute *attr,
4520 const char *buf, size_t count)
4521{
4522 struct wl1271 *wl = dev_get_drvdata(dev);
4523 unsigned long res;
4524 int ret;
4525
Luciano Coelho6277ed62011-04-01 17:49:54 +03004526 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004527 if (ret < 0) {
4528 wl1271_warning("incorrect value written to bt_coex_mode");
4529 return count;
4530 }
4531
4532 mutex_lock(&wl->mutex);
4533
4534 res = !!res;
4535
4536 if (res == wl->sg_enabled)
4537 goto out;
4538
4539 wl->sg_enabled = res;
4540
4541 if (wl->state == WL1271_STATE_OFF)
4542 goto out;
4543
Ido Yariva6208652011-03-01 15:14:41 +02004544 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004545 if (ret < 0)
4546 goto out;
4547
4548 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4549 wl1271_ps_elp_sleep(wl);
4550
4551 out:
4552 mutex_unlock(&wl->mutex);
4553 return count;
4554}
4555
4556static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4557 wl1271_sysfs_show_bt_coex_state,
4558 wl1271_sysfs_store_bt_coex_state);
4559
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004560static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4561 struct device_attribute *attr,
4562 char *buf)
4563{
4564 struct wl1271 *wl = dev_get_drvdata(dev);
4565 ssize_t len;
4566
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004567 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004568
4569 mutex_lock(&wl->mutex);
4570 if (wl->hw_pg_ver >= 0)
4571 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4572 else
4573 len = snprintf(buf, len, "n/a\n");
4574 mutex_unlock(&wl->mutex);
4575
4576 return len;
4577}
4578
Gery Kahn6f07b722011-07-18 14:21:49 +03004579static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004580 wl1271_sysfs_show_hw_pg_ver, NULL);
4581
Ido Yariv95dac04f2011-06-06 14:57:06 +03004582static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4583 struct bin_attribute *bin_attr,
4584 char *buffer, loff_t pos, size_t count)
4585{
4586 struct device *dev = container_of(kobj, struct device, kobj);
4587 struct wl1271 *wl = dev_get_drvdata(dev);
4588 ssize_t len;
4589 int ret;
4590
4591 ret = mutex_lock_interruptible(&wl->mutex);
4592 if (ret < 0)
4593 return -ERESTARTSYS;
4594
4595 /* Let only one thread read the log at a time, blocking others */
4596 while (wl->fwlog_size == 0) {
4597 DEFINE_WAIT(wait);
4598
4599 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4600 &wait,
4601 TASK_INTERRUPTIBLE);
4602
4603 if (wl->fwlog_size != 0) {
4604 finish_wait(&wl->fwlog_waitq, &wait);
4605 break;
4606 }
4607
4608 mutex_unlock(&wl->mutex);
4609
4610 schedule();
4611 finish_wait(&wl->fwlog_waitq, &wait);
4612
4613 if (signal_pending(current))
4614 return -ERESTARTSYS;
4615
4616 ret = mutex_lock_interruptible(&wl->mutex);
4617 if (ret < 0)
4618 return -ERESTARTSYS;
4619 }
4620
4621 /* Check if the fwlog is still valid */
4622 if (wl->fwlog_size < 0) {
4623 mutex_unlock(&wl->mutex);
4624 return 0;
4625 }
4626
4627 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4628 len = min(count, (size_t)wl->fwlog_size);
4629 wl->fwlog_size -= len;
4630 memcpy(buffer, wl->fwlog, len);
4631
4632 /* Make room for new messages */
4633 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4634
4635 mutex_unlock(&wl->mutex);
4636
4637 return len;
4638}
4639
4640static struct bin_attribute fwlog_attr = {
4641 .attr = {.name = "fwlog", .mode = S_IRUSR},
4642 .read = wl1271_sysfs_read_fwlog,
4643};
4644
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004645int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004646{
4647 int ret;
4648
4649 if (wl->mac80211_registered)
4650 return 0;
4651
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004652 ret = wl1271_fetch_nvs(wl);
4653 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004654 /* NOTE: The wl->nvs->nvs element must be first, in
4655 * order to simplify the casting, we assume it is at
4656 * the beginning of the wl->nvs structure.
4657 */
4658 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004659
4660 wl->mac_addr[0] = nvs_ptr[11];
4661 wl->mac_addr[1] = nvs_ptr[10];
4662 wl->mac_addr[2] = nvs_ptr[6];
4663 wl->mac_addr[3] = nvs_ptr[5];
4664 wl->mac_addr[4] = nvs_ptr[4];
4665 wl->mac_addr[5] = nvs_ptr[3];
4666 }
4667
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004668 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4669
4670 ret = ieee80211_register_hw(wl->hw);
4671 if (ret < 0) {
4672 wl1271_error("unable to register mac80211 hw: %d", ret);
4673 return ret;
4674 }
4675
4676 wl->mac80211_registered = true;
4677
Eliad Pellerd60080a2010-11-24 12:53:16 +02004678 wl1271_debugfs_init(wl);
4679
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004680 register_netdevice_notifier(&wl1271_dev_notifier);
4681
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004682 wl1271_notice("loaded");
4683
4684 return 0;
4685}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004686EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004687
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004688void wl1271_unregister_hw(struct wl1271 *wl)
4689{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004690 if (wl->state == WL1271_STATE_PLT)
4691 __wl1271_plt_stop(wl);
4692
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004693 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004694 ieee80211_unregister_hw(wl->hw);
4695 wl->mac80211_registered = false;
4696
4697}
4698EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4699
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004700int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004701{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004702 static const u32 cipher_suites[] = {
4703 WLAN_CIPHER_SUITE_WEP40,
4704 WLAN_CIPHER_SUITE_WEP104,
4705 WLAN_CIPHER_SUITE_TKIP,
4706 WLAN_CIPHER_SUITE_CCMP,
4707 WL1271_CIPHER_SUITE_GEM,
4708 };
4709
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004710 /* The tx descriptor buffer and the TKIP space. */
4711 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4712 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004713
4714 /* unit us */
4715 /* FIXME: find a proper value */
4716 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004717 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004718
4719 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004720 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004721 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004722 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004723 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004724 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004725 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004726 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004727 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004728 IEEE80211_HW_AP_LINK_PS |
4729 IEEE80211_HW_AMPDU_AGGREGATION |
4730 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004731
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004732 wl->hw->wiphy->cipher_suites = cipher_suites;
4733 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4734
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004735 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004736 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4737 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004738 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004739 wl->hw->wiphy->max_sched_scan_ssids = 16;
4740 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004741 /*
4742 * Maximum length of elements in scanning probe request templates
4743 * should be the maximum length possible for a template, without
4744 * the IEEE80211 header of the template
4745 */
Eliad Peller154037d2011-08-14 13:17:12 +03004746 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004747 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004748
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004749 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4750 sizeof(struct ieee80211_header);
4751
Eliad Peller1ec23f72011-08-25 14:26:54 +03004752 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4753
Luciano Coelho4a31c112011-03-21 23:16:14 +02004754 /* make sure all our channels fit in the scanned_ch bitmask */
4755 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4756 ARRAY_SIZE(wl1271_channels_5ghz) >
4757 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004758 /*
4759 * We keep local copies of the band structs because we need to
4760 * modify them on a per-device basis.
4761 */
4762 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4763 sizeof(wl1271_band_2ghz));
4764 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4765 sizeof(wl1271_band_5ghz));
4766
4767 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4768 &wl->bands[IEEE80211_BAND_2GHZ];
4769 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4770 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004771
Kalle Valo12bd8942010-03-18 12:26:33 +02004772 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004773 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004774
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004775 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4776
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004777 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004778
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004779 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004780 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004781
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004782 wl->hw->max_rx_aggregation_subframes = 8;
4783
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004784 return 0;
4785}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004786EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004787
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004788#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004789
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004790struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004791{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004792 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004793 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004794 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004795 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004796 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004797
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004798 BUILD_BUG_ON(AP_MAX_LINKS > WL12XX_MAX_LINKS);
4799
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004800 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4801 if (!hw) {
4802 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004803 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004804 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004805 }
4806
Julia Lawall929ebd32010-05-15 23:16:39 +02004807 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004808 if (!plat_dev) {
4809 wl1271_error("could not allocate platform_device");
4810 ret = -ENOMEM;
4811 goto err_plat_alloc;
4812 }
4813
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004814 wl = hw->priv;
4815 memset(wl, 0, sizeof(*wl));
4816
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004817 INIT_LIST_HEAD(&wl->list);
4818
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004819 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004820 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004821
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004822 for (i = 0; i < NUM_TX_QUEUES; i++)
4823 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004824
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004825 for (i = 0; i < NUM_TX_QUEUES; i++)
4826 for (j = 0; j < AP_MAX_LINKS; j++)
4827 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4828
Ido Yariva6208652011-03-01 15:14:41 +02004829 skb_queue_head_init(&wl->deferred_rx_queue);
4830 skb_queue_head_init(&wl->deferred_tx_queue);
4831
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004832 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004833 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004834 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004835 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4836 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4837 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004838 INIT_WORK(&wl->rx_streaming_enable_work,
4839 wl1271_rx_streaming_enable_work);
4840 INIT_WORK(&wl->rx_streaming_disable_work,
4841 wl1271_rx_streaming_disable_work);
4842
Eliad Peller92ef8962011-06-07 12:50:46 +03004843 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4844 if (!wl->freezable_wq) {
4845 ret = -ENOMEM;
4846 goto err_hw;
4847 }
4848
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004849 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004850 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004851 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004852 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004853 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004854 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004855 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004856 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004857 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004858 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004859 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004860 wl->bss_type = MAX_BSS_TYPE;
4861 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004862 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004863 wl->ap_ps_map = 0;
4864 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004865 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004866 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004867 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004868 wl->tx_security_seq = 0;
4869 wl->tx_security_last_seq_lsb = 0;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03004870 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Peller7f0979882011-08-14 13:17:06 +03004871 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004872 wl->system_hlid = WL12XX_SYSTEM_HLID;
Eliad Peller7f0979882011-08-14 13:17:06 +03004873 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004874 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4875 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsov712e9bf2011-08-14 13:17:20 +03004876 wl->session_counter = 0;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03004877 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
4878 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsovda032092011-08-25 12:43:15 +03004879 wl->active_sta_count = 0;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004880 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4881 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004882 wl->fwlog_size = 0;
4883 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004884
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004885 /* The system link is always allocated */
4886 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4887
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004888 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004889 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004890 wl->tx_frames[i] = NULL;
4891
4892 spin_lock_init(&wl->wl_lock);
4893
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004894 wl->state = WL1271_STATE_OFF;
4895 mutex_init(&wl->mutex);
4896
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004897 /* Apply default driver configuration. */
4898 wl1271_conf_init(wl);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004899 wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
4900 wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004901
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004902 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4903 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4904 if (!wl->aggr_buf) {
4905 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004906 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004907 }
4908
Ido Yariv990f5de2011-03-31 10:06:59 +02004909 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4910 if (!wl->dummy_packet) {
4911 ret = -ENOMEM;
4912 goto err_aggr;
4913 }
4914
Ido Yariv95dac04f2011-06-06 14:57:06 +03004915 /* Allocate one page for the FW log */
4916 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4917 if (!wl->fwlog) {
4918 ret = -ENOMEM;
4919 goto err_dummy_packet;
4920 }
4921
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004922 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004923 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004924 if (ret) {
4925 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004926 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004927 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004928 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004929
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004930 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004931 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004932 if (ret < 0) {
4933 wl1271_error("failed to create sysfs file bt_coex_state");
4934 goto err_platform;
4935 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004936
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004937 /* Create sysfs file to get HW PG version */
4938 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4939 if (ret < 0) {
4940 wl1271_error("failed to create sysfs file hw_pg_ver");
4941 goto err_bt_coex_state;
4942 }
4943
Ido Yariv95dac04f2011-06-06 14:57:06 +03004944 /* Create sysfs file for the FW log */
4945 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4946 if (ret < 0) {
4947 wl1271_error("failed to create sysfs file fwlog");
4948 goto err_hw_pg_ver;
4949 }
4950
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004951 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004952
Ido Yariv95dac04f2011-06-06 14:57:06 +03004953err_hw_pg_ver:
4954 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4955
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004956err_bt_coex_state:
4957 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4958
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004959err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004960 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004961
Ido Yariv95dac04f2011-06-06 14:57:06 +03004962err_fwlog:
4963 free_page((unsigned long)wl->fwlog);
4964
Ido Yariv990f5de2011-03-31 10:06:59 +02004965err_dummy_packet:
4966 dev_kfree_skb(wl->dummy_packet);
4967
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004968err_aggr:
4969 free_pages((unsigned long)wl->aggr_buf, order);
4970
Eliad Peller92ef8962011-06-07 12:50:46 +03004971err_wq:
4972 destroy_workqueue(wl->freezable_wq);
4973
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004974err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004975 wl1271_debugfs_exit(wl);
4976 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004977
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004978err_plat_alloc:
4979 ieee80211_free_hw(hw);
4980
4981err_hw_alloc:
4982
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004983 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004984}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004985EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004986
4987int wl1271_free_hw(struct wl1271 *wl)
4988{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004989 /* Unblock any fwlog readers */
4990 mutex_lock(&wl->mutex);
4991 wl->fwlog_size = -1;
4992 wake_up_interruptible_all(&wl->fwlog_waitq);
4993 mutex_unlock(&wl->mutex);
4994
4995 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004996
4997 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4998
4999 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005000 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005001 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005002 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005003 free_pages((unsigned long)wl->aggr_buf,
5004 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005005 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005006
5007 wl1271_debugfs_exit(wl);
5008
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005009 vfree(wl->fw);
5010 wl->fw = NULL;
5011 kfree(wl->nvs);
5012 wl->nvs = NULL;
5013
5014 kfree(wl->fw_status);
5015 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005016 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005017
5018 ieee80211_free_hw(wl->hw);
5019
5020 return 0;
5021}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005022EXPORT_SYMBOL_GPL(wl1271_free_hw);
5023
Guy Eilam491bbd62011-01-12 10:33:29 +01005024u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005025EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005026module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005027MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5028
Ido Yariv95dac04f2011-06-06 14:57:06 +03005029module_param_named(fwlog, fwlog_param, charp, 0);
5030MODULE_PARM_DESC(keymap,
5031 "FW logger options: continuous, ondemand, dbgpins or disable");
5032
Eliad Peller2a5bff02011-08-25 18:10:59 +03005033module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5034MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5035
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005036MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005037MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005038MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");