blob: d19c3fe348600c485d4d18326758780fa59bb621 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000038#include "reg.h"
39#include "io.h"
40#include "event.h"
41#include "tx.h"
42#include "rx.h"
43#include "ps.h"
44#include "init.h"
45#include "debugfs.h"
46#include "cmd.h"
47#include "boot.h"
48#include "testmode.h"
49#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030050
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020051#define WL1271_BOOT_RETRIES 3
52
Juuso Oikarinen8a080482009-10-13 12:47:44 +030053static struct conf_drv_settings default_conf = {
54 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030055 .params = {
56 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
57 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
58 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
61 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
62 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
64 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
65 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
66 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
68 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
69 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
70 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
71 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
73 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
74 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
75 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
76 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
77 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
78 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
79 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
82 /* active scan params */
83 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
84 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
85 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
86 /* passive scan params */
87 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
88 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
90 /* passive scan in dual antenna params */
91 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
92 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
93 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
94 /* general params */
95 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
96 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
97 [CONF_SG_BEACON_MISS_PERCENT] = 60,
98 [CONF_SG_DHCP_TIME] = 5000,
99 [CONF_SG_RXT] = 1200,
100 [CONF_SG_TXT] = 1000,
101 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
102 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
103 [CONF_SG_HV3_MAX_SERVED] = 6,
104 [CONF_SG_PS_POLL_TIMEOUT] = 10,
105 [CONF_SG_UPSD_TIMEOUT] = 10,
106 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
107 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
108 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
109 /* AP params */
110 [CONF_AP_BEACON_MISS_TX] = 3,
111 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
112 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
113 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
114 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
115 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300116 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200117 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300118 },
119 .rx = {
120 .rx_msdu_life_time = 512000,
121 .packet_detection_threshold = 0,
122 .ps_poll_timeout = 15,
123 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300124 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200125 .rx_cca_threshold = 0,
126 .irq_blk_threshold = 0xFFFF,
127 .irq_pkt_threshold = 0,
128 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300129 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
130 },
131 .tx = {
132 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200133 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300134 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .short_retry_limit = 10,
136 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200137 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300138 },
139 .ac_conf_count = 4,
140 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_BE,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = 3,
146 .tx_op_limit = 0,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_BK,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = 7,
153 .tx_op_limit = 0,
154 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200155 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300156 .ac = CONF_TX_AC_VI,
157 .cw_min = 15,
158 .cw_max = 63,
159 .aifsn = CONF_TX_AIFS_PIFS,
160 .tx_op_limit = 3008,
161 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200162 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300163 .ac = CONF_TX_AC_VO,
164 .cw_min = 15,
165 .cw_max = 63,
166 .aifsn = CONF_TX_AIFS_PIFS,
167 .tx_op_limit = 1504,
168 },
169 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300170 .max_tx_retries = 100,
171 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200172 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300173 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 [CONF_TX_AC_BE] = {
175 .queue_id = CONF_TX_AC_BE,
176 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .tsid = CONF_TX_AC_BE,
178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200182 [CONF_TX_AC_BK] = {
183 .queue_id = CONF_TX_AC_BK,
184 .channel_type = CONF_CHANNEL_TYPE_EDCF,
185 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_VI] = {
191 .queue_id = CONF_TX_AC_VI,
192 .channel_type = CONF_CHANNEL_TYPE_EDCF,
193 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300194 .ps_scheme = CONF_PS_SCHEME_LEGACY,
195 .ack_policy = CONF_ACK_POLICY_LEGACY,
196 .apsd_conf = {0, 0},
197 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200198 [CONF_TX_AC_VO] = {
199 .queue_id = CONF_TX_AC_VO,
200 .channel_type = CONF_CHANNEL_TYPE_EDCF,
201 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300202 .ps_scheme = CONF_PS_SCHEME_LEGACY,
203 .ack_policy = CONF_ACK_POLICY_LEGACY,
204 .apsd_conf = {0, 0},
205 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300206 },
207 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200208 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300209 .tx_compl_threshold = 4,
210 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
211 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200212 .tmpl_short_retry_limit = 10,
213 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300214 },
215 .conn = {
216 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300217 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300219 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_ie = {
221 [0] = {
222 .ie = WLAN_EID_CHANNEL_SWITCH,
223 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300224 },
225 [1] = {
226 .ie = WLAN_EID_HT_INFORMATION,
227 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200230 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 .bss_lose_timeout = 100,
232 .beacon_rx_timeout = 10000,
233 .broadcast_timeout = 20000,
234 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300235 .ps_poll_threshold = 10,
236 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300237 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200238 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300239 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300240 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200241 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300242 .keep_alive_interval = 55000,
243 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300244 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200245 .itrim = {
246 .enable = false,
247 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200248 },
249 .pm_config = {
250 .host_clk_settling_time = 5000,
251 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300252 },
253 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 .trigger_pacing = 1,
255 .avg_weight_rssi_beacon = 20,
256 .avg_weight_rssi_data = 10,
257 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100258 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200259 },
260 .scan = {
261 .min_dwell_time_active = 7500,
262 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100263 .min_dwell_time_passive = 100000,
264 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200265 .num_probe_reqs = 2,
266 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300267 .sched_scan = {
268 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300269 .min_dwell_time_active = 30,
270 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300271 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300272 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .num_probe_reqs = 2,
274 .rssi_threshold = -90,
275 .snr_threshold = 0,
276 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200277 .rf = {
278 .tx_per_channel_power_compensation_2 = {
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 },
281 .tx_per_channel_power_compensation_5 = {
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 },
286 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100287 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300288 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .tx_ba_win_size = 64,
290 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300291 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100292 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200293 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200294 .num_stations = 1,
295 .ssid_profiles = 1,
296 .rx_block_num = 70,
297 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300298 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200299 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200300 .min_req_rx_blocks = 22,
301 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200302 },
303 .mem_wl128x = {
304 .num_stations = 1,
305 .ssid_profiles = 1,
306 .rx_block_num = 40,
307 .tx_min_block_num = 40,
308 .dynamic_memory = 1,
309 .min_req_tx_blocks = 45,
310 .min_req_rx_blocks = 22,
311 .tx_min = 27,
312 },
Shahar Leviff868432011-04-11 15:41:46 +0300313 .fm_coex = {
314 .enable = true,
315 .swallow_period = 5,
316 .n_divider_fref_set_1 = 0xff, /* default */
317 .n_divider_fref_set_2 = 12,
318 .m_divider_fref_set_1 = 148,
319 .m_divider_fref_set_2 = 0xffff, /* default */
320 .coex_pll_stabilization_time = 0xffffffff, /* default */
321 .ldo_stabilization_time = 0xffff, /* default */
322 .fm_disturbed_band_margin = 0xff, /* default */
323 .swallow_clk_diff = 0xff, /* default */
324 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300325 .rx_streaming = {
326 .duration = 150,
327 .queues = 0x1,
328 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300329 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300330 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300331 .fwlog = {
332 .mode = WL12XX_FWLOG_ON_DEMAND,
333 .mem_blocks = 2,
334 .severity = 0,
335 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
336 .output = WL12XX_FWLOG_OUTPUT_HOST,
337 .threshold = 0,
338 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300339 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300340 .rate = {
341 .rate_retry_score = 32000,
342 .per_add = 8192,
343 .per_th1 = 2048,
344 .per_th2 = 4096,
345 .max_per = 8100,
346 .inverse_curiosity_factor = 5,
347 .tx_fail_low_th = 4,
348 .tx_fail_high_th = 10,
349 .per_alpha_shift = 4,
350 .per_add_shift = 13,
351 .per_beta1_shift = 10,
352 .per_beta2_shift = 8,
353 .rate_check_up = 2,
354 .rate_check_down = 12,
355 .rate_retry_policy = {
356 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00,
359 },
360 },
Eliad Peller94877752011-08-28 15:11:56 +0300361 .hangover = {
362 .recover_time = 0,
363 .hangover_period = 20,
364 .dynamic_mode = 1,
365 .early_termination_mode = 1,
366 .max_period = 20,
367 .min_period = 1,
368 .increase_delta = 1,
369 .decrease_delta = 2,
370 .quiet_time = 4,
371 .increase_time = 1,
372 .window_size = 16,
373 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300374};
375
Ido Yariv95dac04f2011-06-06 14:57:06 +0300376static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300377static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300379static void __wl1271_op_remove_interface(struct wl1271 *wl,
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 Yarivbaacb9a2011-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 Yarivbaacb9a2011-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 Yarivbaacb9a2011-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 Yarivbaacb9a2011-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 Nemtsov04b4d692011-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
Johannes Berg3b40c042011-07-13 10:39:16 +02002101 memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002102 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002103 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002104 wl->set_bss_type = MAX_BSS_TYPE;
Eliad Peller045c7452011-08-28 15:23:01 +03002105 wl->p2p = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002106 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002107
2108 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002109 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002110 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
2111 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002112 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002113 wl->tx_results_count = 0;
2114 wl->tx_packets_count = 0;
2115 wl->time_offset = 0;
2116 wl->session_counter = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03002117 wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
2118 wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002119 wl->vif = NULL;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002120 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002121 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002122 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02002123 wl->ap_fw_ps_map = 0;
2124 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002125 wl->sched_scanning = false;
Eliad Peller7f0979882011-08-14 13:17:06 +03002126 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002127 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerc690ec82011-08-14 13:17:07 +03002128 memset(wl->roles_map, 0, sizeof(wl->roles_map));
2129 memset(wl->links_map, 0, sizeof(wl->links_map));
Eliad Peller251c1772011-08-14 13:17:17 +03002130 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Arik Nemtsovda032092011-08-25 12:43:15 +03002131 wl->active_sta_count = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002132
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002133 /* The system link is always allocated */
2134 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
2135
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002136 /*
2137 * this is performed after the cancel_work calls and the associated
2138 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2139 * get executed before all these vars have been reset.
2140 */
2141 wl->flags = 0;
2142
Eliad Peller4d56ad92011-08-14 13:17:05 +03002143 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002144
Arik Nemtsov742246f2011-08-14 13:17:33 +03002145 for (i = 0; i < NUM_TX_QUEUES; i++) {
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002146 wl->tx_pkts_freed[i] = 0;
Arik Nemtsov742246f2011-08-14 13:17:33 +03002147 wl->tx_allocated_pkts[i] = 0;
2148 }
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002149
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002150 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002151
2152 kfree(wl->fw_status);
2153 wl->fw_status = NULL;
2154 kfree(wl->tx_res_if);
2155 wl->tx_res_if = NULL;
2156 kfree(wl->target_mem_map);
2157 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002158}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002159
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002160static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2161 struct ieee80211_vif *vif)
2162{
2163 struct wl1271 *wl = hw->priv;
2164
2165 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002166 /*
2167 * wl->vif can be null here if someone shuts down the interface
2168 * just when hardware recovery has been started.
2169 */
2170 if (wl->vif) {
2171 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002172 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002173 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002174
Juuso Oikarinen67353292010-11-18 15:19:02 +02002175 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002176 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002177}
2178
Eliad Peller87fbcb02011-10-05 11:55:41 +02002179static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2180 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002181{
2182 int ret;
Eliad Peller227e81e2011-08-14 13:17:26 +03002183 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002184
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002185 /*
2186 * One of the side effects of the JOIN command is that is clears
2187 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2188 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002189 * Currently the only valid scenario for JOIN during association
2190 * is on roaming, in which case we will also be given new keys.
2191 * Keep the below message for now, unless it starts bothering
2192 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002193 */
2194 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2195 wl1271_info("JOIN while associated.");
2196
2197 if (set_assoc)
2198 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2199
Eliad Peller227e81e2011-08-14 13:17:26 +03002200 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002201 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002202 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002203 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002204 if (ret < 0)
2205 goto out;
2206
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002207 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2208 goto out;
2209
2210 /*
2211 * The join command disable the keep-alive mode, shut down its process,
2212 * and also clear the template config, so we need to reset it all after
2213 * the join. The acx_aid starts the keep-alive process, and the order
2214 * of the commands below is relevant.
2215 */
2216 ret = wl1271_acx_keep_alive_mode(wl, true);
2217 if (ret < 0)
2218 goto out;
2219
2220 ret = wl1271_acx_aid(wl, wl->aid);
2221 if (ret < 0)
2222 goto out;
2223
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002224 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002225 if (ret < 0)
2226 goto out;
2227
2228 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2229 ACX_KEEP_ALIVE_TPL_VALID);
2230 if (ret < 0)
2231 goto out;
2232
2233out:
2234 return ret;
2235}
2236
2237static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002238{
2239 int ret;
2240
Shahar Levi6d158ff2011-09-08 13:01:33 +03002241 if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags)) {
2242 wl12xx_cmd_stop_channel_switch(wl);
2243 ieee80211_chswitch_done(wl->vif, false);
2244 }
2245
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002246 /* to stop listening to a channel, we disconnect */
Eliad Pellerc690ec82011-08-14 13:17:07 +03002247 ret = wl12xx_cmd_role_stop_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002248 if (ret < 0)
2249 goto out;
2250
Oz Krakowskib992c682011-06-26 10:36:02 +03002251 /* reset TX security counters on a clean disconnect */
2252 wl->tx_security_last_seq_lsb = 0;
2253 wl->tx_security_seq = 0;
2254
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002255out:
2256 return ret;
2257}
2258
Eliad Peller87fbcb02011-10-05 11:55:41 +02002259static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002260{
Eliad Peller87fbcb02011-10-05 11:55:41 +02002261 wlvif->basic_rate_set = wl->bitrate_masks[wl->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002262 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002263}
2264
Eliad Peller251c1772011-08-14 13:17:17 +03002265static bool wl12xx_is_roc(struct wl1271 *wl)
2266{
2267 u8 role_id;
2268
2269 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2270 if (role_id >= WL12XX_MAX_ROLES)
2271 return false;
2272
2273 return true;
2274}
2275
Eliad Peller87fbcb02011-10-05 11:55:41 +02002276static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2277 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002278{
2279 int ret;
2280
2281 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002282 /* no need to croc if we weren't busy (e.g. during boot) */
2283 if (wl12xx_is_roc(wl)) {
2284 ret = wl12xx_croc(wl, wl->dev_role_id);
2285 if (ret < 0)
2286 goto out;
2287
2288 ret = wl12xx_cmd_role_stop_dev(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002289 if (ret < 0)
2290 goto out;
2291 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002292 wlvif->rate_set =
2293 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2294 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002295 if (ret < 0)
2296 goto out;
2297 ret = wl1271_acx_keep_alive_config(
2298 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2299 ACX_KEEP_ALIVE_TPL_INVALID);
2300 if (ret < 0)
2301 goto out;
2302 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2303 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002304 /* The current firmware only supports sched_scan in idle */
2305 if (wl->sched_scanning) {
2306 wl1271_scan_sched_scan_stop(wl);
2307 ieee80211_sched_scan_stopped(wl->hw);
2308 }
2309
Eliad Peller251c1772011-08-14 13:17:17 +03002310 ret = wl12xx_cmd_role_start_dev(wl);
2311 if (ret < 0)
2312 goto out;
2313
2314 ret = wl12xx_roc(wl, wl->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002315 if (ret < 0)
2316 goto out;
2317 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2318 }
2319
2320out:
2321 return ret;
2322}
2323
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002324static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2325{
2326 struct wl1271 *wl = hw->priv;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002327 struct ieee80211_vif *vif = wl->vif; /* TODO: reconfig all vifs */
2328 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002329 struct ieee80211_conf *conf = &hw->conf;
2330 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002331 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002332
2333 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2334
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002335 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2336 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002337 channel,
2338 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002339 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002340 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2341 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002342
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002343 /*
2344 * mac80211 will go to idle nearly immediately after transmitting some
2345 * frames, such as the deauth. To make sure those frames reach the air,
2346 * wait here until the TX queue is fully flushed.
2347 */
2348 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2349 (conf->flags & IEEE80211_CONF_IDLE))
2350 wl1271_tx_flush(wl);
2351
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002352 mutex_lock(&wl->mutex);
2353
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002354 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002355 /* we support configuring the channel and band while off */
2356 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2357 wl->band = conf->channel->band;
2358 wl->channel = channel;
2359 }
2360
Arik Nemtsov097f8822011-06-27 22:06:34 +03002361 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2362 wl->power_level = conf->power_level;
2363
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002364 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002365 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002366
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002367 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2368
Ido Yariva6208652011-03-01 15:14:41 +02002369 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002370 if (ret < 0)
2371 goto out;
2372
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002373 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002374 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2375 ((wl->band != conf->channel->band) ||
2376 (wl->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002377 /* send all pending packets */
2378 wl1271_tx_work_locked(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002379 wl->band = conf->channel->band;
2380 wl->channel = channel;
2381
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002382 if (!is_ap) {
2383 /*
2384 * FIXME: the mac80211 should really provide a fixed
2385 * rate to use here. for now, just use the smallest
2386 * possible rate for the band as a fixed rate for
2387 * association frames and other control messages.
2388 */
2389 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002390 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002391
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002392 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002393 wl1271_tx_min_rate_get(wl,
2394 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002395 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002396 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002397 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002398 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002399
Eliad Peller251c1772011-08-14 13:17:17 +03002400 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2401 if (wl12xx_is_roc(wl)) {
2402 /* roaming */
2403 ret = wl12xx_croc(wl, wl->dev_role_id);
2404 if (ret < 0)
2405 goto out_sleep;
2406 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002407 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002408 if (ret < 0)
2409 wl1271_warning("cmd join on channel "
2410 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002411 } else {
2412 /*
2413 * change the ROC channel. do it only if we are
2414 * not idle. otherwise, CROC will be called
2415 * anyway.
2416 */
2417 if (wl12xx_is_roc(wl) &&
2418 !(conf->flags & IEEE80211_CONF_IDLE)) {
2419 ret = wl12xx_croc(wl, wl->dev_role_id);
2420 if (ret < 0)
2421 goto out_sleep;
2422
2423 ret = wl12xx_roc(wl, wl->dev_role_id);
2424 if (ret < 0)
2425 wl1271_warning("roc failed %d",
2426 ret);
2427 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002428 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002429 }
2430 }
2431
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002432 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002433 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002434 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002435 if (ret < 0)
2436 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002437 }
2438
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002439 /*
2440 * if mac80211 changes the PSM mode, make sure the mode is not
2441 * incorrectly changed after the pspoll failure active window.
2442 */
2443 if (changed & IEEE80211_CONF_CHANGE_PS)
2444 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2445
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002446 if (conf->flags & IEEE80211_CONF_PS &&
2447 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2448 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002449
2450 /*
2451 * We enter PSM only if we're already associated.
2452 * If we're not, we'll enter it when joining an SSID,
2453 * through the bss_info_changed() hook.
2454 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002455 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002456 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002457 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002458 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002459 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002460 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002461 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002462 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002463
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002464 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002465
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002466 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002467 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002468 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002469 }
2470
2471 if (conf->power_level != wl->power_level) {
2472 ret = wl1271_acx_tx_power(wl, conf->power_level);
2473 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002474 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002475
2476 wl->power_level = conf->power_level;
2477 }
2478
2479out_sleep:
2480 wl1271_ps_elp_sleep(wl);
2481
2482out:
2483 mutex_unlock(&wl->mutex);
2484
2485 return ret;
2486}
2487
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002488struct wl1271_filter_params {
2489 bool enabled;
2490 int mc_list_length;
2491 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2492};
2493
Jiri Pirko22bedad2010-04-01 21:22:57 +00002494static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2495 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002496{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002497 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002498 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002499 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002500
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002501 if (unlikely(wl->state == WL1271_STATE_OFF))
2502 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002503
Juuso Oikarinen74441132009-10-13 12:47:53 +03002504 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002505 if (!fp) {
2506 wl1271_error("Out of memory setting filters.");
2507 return 0;
2508 }
2509
2510 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002511 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002512 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2513 fp->enabled = false;
2514 } else {
2515 fp->enabled = true;
2516 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002517 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002518 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002519 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002520 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002521 }
2522
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002523 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002524}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002525
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002526#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2527 FIF_ALLMULTI | \
2528 FIF_FCSFAIL | \
2529 FIF_BCN_PRBRESP_PROMISC | \
2530 FIF_CONTROL | \
2531 FIF_OTHER_BSS)
2532
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002533static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2534 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002535 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002536{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002537 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002538 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002539 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002540
Arik Nemtsov7d057862010-10-16 19:25:35 +02002541 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2542 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002543
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002544 mutex_lock(&wl->mutex);
2545
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002546 *total &= WL1271_SUPPORTED_FILTERS;
2547 changed &= WL1271_SUPPORTED_FILTERS;
2548
2549 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002550 goto out;
2551
Ido Yariva6208652011-03-01 15:14:41 +02002552 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002553 if (ret < 0)
2554 goto out;
2555
Arik Nemtsov7d057862010-10-16 19:25:35 +02002556 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2557 if (*total & FIF_ALLMULTI)
2558 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2559 else if (fp)
2560 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2561 fp->mc_list,
2562 fp->mc_list_length);
2563 if (ret < 0)
2564 goto out_sleep;
2565 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002566
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002567 /*
2568 * the fw doesn't provide an api to configure the filters. instead,
2569 * the filters configuration is based on the active roles / ROC
2570 * state.
2571 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002572
2573out_sleep:
2574 wl1271_ps_elp_sleep(wl);
2575
2576out:
2577 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002578 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002579}
2580
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002581static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2582 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2583 u16 tx_seq_16)
2584{
2585 struct wl1271_ap_key *ap_key;
2586 int i;
2587
2588 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2589
2590 if (key_size > MAX_KEY_SIZE)
2591 return -EINVAL;
2592
2593 /*
2594 * Find next free entry in ap_keys. Also check we are not replacing
2595 * an existing key.
2596 */
2597 for (i = 0; i < MAX_NUM_KEYS; i++) {
2598 if (wl->recorded_ap_keys[i] == NULL)
2599 break;
2600
2601 if (wl->recorded_ap_keys[i]->id == id) {
2602 wl1271_warning("trying to record key replacement");
2603 return -EINVAL;
2604 }
2605 }
2606
2607 if (i == MAX_NUM_KEYS)
2608 return -EBUSY;
2609
2610 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2611 if (!ap_key)
2612 return -ENOMEM;
2613
2614 ap_key->id = id;
2615 ap_key->key_type = key_type;
2616 ap_key->key_size = key_size;
2617 memcpy(ap_key->key, key, key_size);
2618 ap_key->hlid = hlid;
2619 ap_key->tx_seq_32 = tx_seq_32;
2620 ap_key->tx_seq_16 = tx_seq_16;
2621
2622 wl->recorded_ap_keys[i] = ap_key;
2623 return 0;
2624}
2625
2626static void wl1271_free_ap_keys(struct wl1271 *wl)
2627{
2628 int i;
2629
2630 for (i = 0; i < MAX_NUM_KEYS; i++) {
2631 kfree(wl->recorded_ap_keys[i]);
2632 wl->recorded_ap_keys[i] = NULL;
2633 }
2634}
2635
2636static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2637{
2638 int i, ret = 0;
2639 struct wl1271_ap_key *key;
2640 bool wep_key_added = false;
2641
2642 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002643 u8 hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002644 if (wl->recorded_ap_keys[i] == NULL)
2645 break;
2646
2647 key = wl->recorded_ap_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002648 hlid = key->hlid;
2649 if (hlid == WL12XX_INVALID_LINK_ID)
2650 hlid = wl->ap_bcast_hlid;
2651
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002652 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2653 key->id, key->key_type,
2654 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002655 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002656 key->tx_seq_16);
2657 if (ret < 0)
2658 goto out;
2659
2660 if (key->key_type == KEY_WEP)
2661 wep_key_added = true;
2662 }
2663
2664 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002665 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002666 wl->ap_bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002667 if (ret < 0)
2668 goto out;
2669 }
2670
2671out:
2672 wl1271_free_ap_keys(wl);
2673 return ret;
2674}
2675
2676static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2677 u8 key_size, const u8 *key, u32 tx_seq_32,
2678 u16 tx_seq_16, struct ieee80211_sta *sta)
2679{
2680 int ret;
2681 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2682
2683 if (is_ap) {
2684 struct wl1271_station *wl_sta;
2685 u8 hlid;
2686
2687 if (sta) {
2688 wl_sta = (struct wl1271_station *)sta->drv_priv;
2689 hlid = wl_sta->hlid;
2690 } else {
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002691 hlid = wl->ap_bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002692 }
2693
2694 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2695 /*
2696 * We do not support removing keys after AP shutdown.
2697 * Pretend we do to make mac80211 happy.
2698 */
2699 if (action != KEY_ADD_OR_REPLACE)
2700 return 0;
2701
2702 ret = wl1271_record_ap_key(wl, id,
2703 key_type, key_size,
2704 key, hlid, tx_seq_32,
2705 tx_seq_16);
2706 } else {
2707 ret = wl1271_cmd_set_ap_key(wl, action,
2708 id, key_type, key_size,
2709 key, hlid, tx_seq_32,
2710 tx_seq_16);
2711 }
2712
2713 if (ret < 0)
2714 return ret;
2715 } else {
2716 const u8 *addr;
2717 static const u8 bcast_addr[ETH_ALEN] = {
2718 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2719 };
2720
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002721 /*
2722 * A STA set to GEM cipher requires 2 tx spare blocks.
2723 * Return to default value when GEM cipher key is removed
2724 */
2725 if (key_type == KEY_GEM) {
2726 if (action == KEY_ADD_OR_REPLACE)
2727 wl->tx_spare_blocks = 2;
2728 else if (action == KEY_REMOVE)
2729 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2730 }
2731
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002732 addr = sta ? sta->addr : bcast_addr;
2733
2734 if (is_zero_ether_addr(addr)) {
2735 /* We dont support TX only encryption */
2736 return -EOPNOTSUPP;
2737 }
2738
2739 /* The wl1271 does not allow to remove unicast keys - they
2740 will be cleared automatically on next CMD_JOIN. Ignore the
2741 request silently, as we dont want the mac80211 to emit
2742 an error message. */
2743 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2744 return 0;
2745
Eliad Peller010d3d32011-08-14 13:17:31 +03002746 /* don't remove key if hlid was already deleted */
2747 if (action == KEY_REMOVE &&
2748 wl->sta_hlid == WL12XX_INVALID_LINK_ID)
2749 return 0;
2750
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002751 ret = wl1271_cmd_set_sta_key(wl, action,
2752 id, key_type, key_size,
2753 key, addr, tx_seq_32,
2754 tx_seq_16);
2755 if (ret < 0)
2756 return ret;
2757
2758 /* the default WEP key needs to be configured at least once */
2759 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002760 ret = wl12xx_cmd_set_default_wep_key(wl,
2761 wl->default_key,
2762 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002763 if (ret < 0)
2764 return ret;
2765 }
2766 }
2767
2768 return 0;
2769}
2770
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002771static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2772 struct ieee80211_vif *vif,
2773 struct ieee80211_sta *sta,
2774 struct ieee80211_key_conf *key_conf)
2775{
2776 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002777 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002778 u32 tx_seq_32 = 0;
2779 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002780 u8 key_type;
2781
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002782 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2783
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002784 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002785 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002786 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002787 key_conf->keylen, key_conf->flags);
2788 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2789
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002790 mutex_lock(&wl->mutex);
2791
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002792 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2793 ret = -EAGAIN;
2794 goto out_unlock;
2795 }
2796
Ido Yariva6208652011-03-01 15:14:41 +02002797 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002798 if (ret < 0)
2799 goto out_unlock;
2800
Johannes Berg97359d12010-08-10 09:46:38 +02002801 switch (key_conf->cipher) {
2802 case WLAN_CIPHER_SUITE_WEP40:
2803 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002804 key_type = KEY_WEP;
2805
2806 key_conf->hw_key_idx = key_conf->keyidx;
2807 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002808 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002809 key_type = KEY_TKIP;
2810
2811 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002812 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2813 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002814 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002815 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002816 key_type = KEY_AES;
2817
2818 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002819 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2820 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002821 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002822 case WL1271_CIPHER_SUITE_GEM:
2823 key_type = KEY_GEM;
2824 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2825 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2826 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002827 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002828 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002829
2830 ret = -EOPNOTSUPP;
2831 goto out_sleep;
2832 }
2833
2834 switch (cmd) {
2835 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002836 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2837 key_conf->keyidx, key_type,
2838 key_conf->keylen, key_conf->key,
2839 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002840 if (ret < 0) {
2841 wl1271_error("Could not add or replace key");
2842 goto out_sleep;
2843 }
2844 break;
2845
2846 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002847 ret = wl1271_set_key(wl, KEY_REMOVE,
2848 key_conf->keyidx, key_type,
2849 key_conf->keylen, key_conf->key,
2850 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002851 if (ret < 0) {
2852 wl1271_error("Could not remove key");
2853 goto out_sleep;
2854 }
2855 break;
2856
2857 default:
2858 wl1271_error("Unsupported key cmd 0x%x", cmd);
2859 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002860 break;
2861 }
2862
2863out_sleep:
2864 wl1271_ps_elp_sleep(wl);
2865
2866out_unlock:
2867 mutex_unlock(&wl->mutex);
2868
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002869 return ret;
2870}
2871
2872static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002873 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002874 struct cfg80211_scan_request *req)
2875{
2876 struct wl1271 *wl = hw->priv;
2877 int ret;
2878 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002879 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002880
2881 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2882
2883 if (req->n_ssids) {
2884 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002885 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002886 }
2887
2888 mutex_lock(&wl->mutex);
2889
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002890 if (wl->state == WL1271_STATE_OFF) {
2891 /*
2892 * We cannot return -EBUSY here because cfg80211 will expect
2893 * a call to ieee80211_scan_completed if we do - in this case
2894 * there won't be any call.
2895 */
2896 ret = -EAGAIN;
2897 goto out;
2898 }
2899
Ido Yariva6208652011-03-01 15:14:41 +02002900 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002901 if (ret < 0)
2902 goto out;
2903
Eliad Peller251c1772011-08-14 13:17:17 +03002904 /* cancel ROC before scanning */
2905 if (wl12xx_is_roc(wl)) {
2906 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2907 /* don't allow scanning right now */
2908 ret = -EBUSY;
2909 goto out_sleep;
2910 }
2911 wl12xx_croc(wl, wl->dev_role_id);
2912 wl12xx_cmd_role_stop_dev(wl);
2913 }
2914
Eliad Peller784f6942011-10-05 11:55:39 +02002915 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002916out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002917 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002918out:
2919 mutex_unlock(&wl->mutex);
2920
2921 return ret;
2922}
2923
Eliad Peller73ecce32011-06-27 13:06:45 +03002924static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2925 struct ieee80211_vif *vif)
2926{
2927 struct wl1271 *wl = hw->priv;
2928 int ret;
2929
2930 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2931
2932 mutex_lock(&wl->mutex);
2933
2934 if (wl->state == WL1271_STATE_OFF)
2935 goto out;
2936
2937 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2938 goto out;
2939
2940 ret = wl1271_ps_elp_wakeup(wl);
2941 if (ret < 0)
2942 goto out;
2943
2944 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2945 ret = wl1271_scan_stop(wl);
2946 if (ret < 0)
2947 goto out_sleep;
2948 }
2949 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2950 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002951 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03002952 wl->scan.req = NULL;
2953 ieee80211_scan_completed(wl->hw, true);
2954
2955out_sleep:
2956 wl1271_ps_elp_sleep(wl);
2957out:
2958 mutex_unlock(&wl->mutex);
2959
2960 cancel_delayed_work_sync(&wl->scan_complete_work);
2961}
2962
Luciano Coelho33c2c062011-05-10 14:46:02 +03002963static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2964 struct ieee80211_vif *vif,
2965 struct cfg80211_sched_scan_request *req,
2966 struct ieee80211_sched_scan_ies *ies)
2967{
2968 struct wl1271 *wl = hw->priv;
2969 int ret;
2970
2971 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2972
2973 mutex_lock(&wl->mutex);
2974
2975 ret = wl1271_ps_elp_wakeup(wl);
2976 if (ret < 0)
2977 goto out;
2978
2979 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2980 if (ret < 0)
2981 goto out_sleep;
2982
2983 ret = wl1271_scan_sched_scan_start(wl);
2984 if (ret < 0)
2985 goto out_sleep;
2986
2987 wl->sched_scanning = true;
2988
2989out_sleep:
2990 wl1271_ps_elp_sleep(wl);
2991out:
2992 mutex_unlock(&wl->mutex);
2993 return ret;
2994}
2995
2996static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2997 struct ieee80211_vif *vif)
2998{
2999 struct wl1271 *wl = hw->priv;
3000 int ret;
3001
3002 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3003
3004 mutex_lock(&wl->mutex);
3005
3006 ret = wl1271_ps_elp_wakeup(wl);
3007 if (ret < 0)
3008 goto out;
3009
3010 wl1271_scan_sched_scan_stop(wl);
3011
3012 wl1271_ps_elp_sleep(wl);
3013out:
3014 mutex_unlock(&wl->mutex);
3015}
3016
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003017static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3018{
3019 struct wl1271 *wl = hw->priv;
3020 int ret = 0;
3021
3022 mutex_lock(&wl->mutex);
3023
3024 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3025 ret = -EAGAIN;
3026 goto out;
3027 }
3028
Ido Yariva6208652011-03-01 15:14:41 +02003029 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003030 if (ret < 0)
3031 goto out;
3032
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003033 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003034 if (ret < 0)
3035 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3036
3037 wl1271_ps_elp_sleep(wl);
3038
3039out:
3040 mutex_unlock(&wl->mutex);
3041
3042 return ret;
3043}
3044
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003045static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3046{
3047 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003048 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003049
3050 mutex_lock(&wl->mutex);
3051
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003052 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3053 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003054 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003055 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003056
Ido Yariva6208652011-03-01 15:14:41 +02003057 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003058 if (ret < 0)
3059 goto out;
3060
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003061 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003062 if (ret < 0)
3063 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
3064
3065 wl1271_ps_elp_sleep(wl);
3066
3067out:
3068 mutex_unlock(&wl->mutex);
3069
3070 return ret;
3071}
3072
Arik Nemtsove78a2872010-10-16 19:07:21 +02003073static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003074 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003075{
Eliad Peller889cb362011-05-01 09:56:45 +03003076 u8 ssid_len;
3077 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3078 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003079
Eliad Peller889cb362011-05-01 09:56:45 +03003080 if (!ptr) {
3081 wl1271_error("No SSID in IEs!");
3082 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003083 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003084
Eliad Peller889cb362011-05-01 09:56:45 +03003085 ssid_len = ptr[1];
3086 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3087 wl1271_error("SSID is too long!");
3088 return -EINVAL;
3089 }
3090
3091 wl->ssid_len = ssid_len;
3092 memcpy(wl->ssid, ptr+2, ssid_len);
3093 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003094}
3095
Eliad Pellerd48055d2011-09-15 12:07:04 +03003096static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3097{
3098 int len;
3099 const u8 *next, *end = skb->data + skb->len;
3100 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3101 skb->len - ieoffset);
3102 if (!ie)
3103 return;
3104 len = ie[1] + 2;
3105 next = ie + len;
3106 memmove(ie, next, end - next);
3107 skb_trim(skb, skb->len - len);
3108}
3109
Eliad Peller26b4bf22011-09-15 12:07:05 +03003110static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3111 unsigned int oui, u8 oui_type,
3112 int ieoffset)
3113{
3114 int len;
3115 const u8 *next, *end = skb->data + skb->len;
3116 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3117 skb->data + ieoffset,
3118 skb->len - ieoffset);
3119 if (!ie)
3120 return;
3121 len = ie[1] + 2;
3122 next = ie + len;
3123 memmove(ie, next, end - next);
3124 skb_trim(skb, skb->len - len);
3125}
3126
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003127static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
3128 u8 *probe_rsp_data,
3129 size_t probe_rsp_len,
3130 u32 rates)
3131{
3132 struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
3133 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3134 int ssid_ie_offset, ie_offset, templ_len;
3135 const u8 *ptr;
3136
3137 /* no need to change probe response if the SSID is set correctly */
3138 if (wl->ssid_len > 0)
3139 return wl1271_cmd_template_set(wl,
3140 CMD_TEMPL_AP_PROBE_RESPONSE,
3141 probe_rsp_data,
3142 probe_rsp_len, 0,
3143 rates);
3144
3145 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3146 wl1271_error("probe_rsp template too big");
3147 return -EINVAL;
3148 }
3149
3150 /* start searching from IE offset */
3151 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3152
3153 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3154 probe_rsp_len - ie_offset);
3155 if (!ptr) {
3156 wl1271_error("No SSID in beacon!");
3157 return -EINVAL;
3158 }
3159
3160 ssid_ie_offset = ptr - probe_rsp_data;
3161 ptr += (ptr[1] + 2);
3162
3163 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3164
3165 /* insert SSID from bss_conf */
3166 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3167 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3168 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3169 bss_conf->ssid, bss_conf->ssid_len);
3170 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3171
3172 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3173 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3174 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3175
3176 return wl1271_cmd_template_set(wl,
3177 CMD_TEMPL_AP_PROBE_RESPONSE,
3178 probe_rsp_templ,
3179 templ_len, 0,
3180 rates);
3181}
3182
Arik Nemtsove78a2872010-10-16 19:07:21 +02003183static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
3184 struct ieee80211_bss_conf *bss_conf,
3185 u32 changed)
3186{
3187 int ret = 0;
3188
3189 if (changed & BSS_CHANGED_ERP_SLOT) {
3190 if (bss_conf->use_short_slot)
3191 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
3192 else
3193 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
3194 if (ret < 0) {
3195 wl1271_warning("Set slot time failed %d", ret);
3196 goto out;
3197 }
3198 }
3199
3200 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3201 if (bss_conf->use_short_preamble)
3202 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
3203 else
3204 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
3205 }
3206
3207 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3208 if (bss_conf->use_cts_prot)
3209 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
3210 else
3211 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
3212 if (ret < 0) {
3213 wl1271_warning("Set ctsprotect failed %d", ret);
3214 goto out;
3215 }
3216 }
3217
3218out:
3219 return ret;
3220}
3221
3222static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3223 struct ieee80211_vif *vif,
3224 struct ieee80211_bss_conf *bss_conf,
3225 u32 changed)
3226{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003227 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003228 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3229 int ret = 0;
3230
3231 if ((changed & BSS_CHANGED_BEACON_INT)) {
3232 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3233 bss_conf->beacon_int);
3234
3235 wl->beacon_int = bss_conf->beacon_int;
3236 }
3237
3238 if ((changed & BSS_CHANGED_BEACON)) {
3239 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003240 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003241 int ieoffset = offsetof(struct ieee80211_mgmt,
3242 u.beacon.variable);
3243 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3244 u16 tmpl_id;
3245
3246 if (!beacon)
3247 goto out;
3248
3249 wl1271_debug(DEBUG_MASTER, "beacon updated");
3250
3251 ret = wl1271_ssid_set(wl, beacon, ieoffset);
3252 if (ret < 0) {
3253 dev_kfree_skb(beacon);
3254 goto out;
3255 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003256 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003257 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3258 CMD_TEMPL_BEACON;
3259 ret = wl1271_cmd_template_set(wl, tmpl_id,
3260 beacon->data,
3261 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003262 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003263 if (ret < 0) {
3264 dev_kfree_skb(beacon);
3265 goto out;
3266 }
3267
Eliad Pellerd48055d2011-09-15 12:07:04 +03003268 /* remove TIM ie from probe response */
3269 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3270
Eliad Peller26b4bf22011-09-15 12:07:05 +03003271 /*
3272 * remove p2p ie from probe response.
3273 * the fw reponds to probe requests that don't include
3274 * the p2p ie. probe requests with p2p ie will be passed,
3275 * and will be responded by the supplicant (the spec
3276 * forbids including the p2p ie when responding to probe
3277 * requests that didn't include it).
3278 */
3279 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3280 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3281
Arik Nemtsove78a2872010-10-16 19:07:21 +02003282 hdr = (struct ieee80211_hdr *) beacon->data;
3283 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3284 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003285 if (is_ap)
3286 ret = wl1271_ap_set_probe_resp_tmpl(wl,
3287 beacon->data,
3288 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003289 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003290 else
3291 ret = wl1271_cmd_template_set(wl,
3292 CMD_TEMPL_PROBE_RESPONSE,
3293 beacon->data,
3294 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003295 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003296 dev_kfree_skb(beacon);
3297 if (ret < 0)
3298 goto out;
3299 }
3300
3301out:
3302 return ret;
3303}
3304
3305/* AP mode changes */
3306static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003307 struct ieee80211_vif *vif,
3308 struct ieee80211_bss_conf *bss_conf,
3309 u32 changed)
3310{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003311 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003312 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003313
Arik Nemtsove78a2872010-10-16 19:07:21 +02003314 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3315 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003316
Eliad Peller87fbcb02011-10-05 11:55:41 +02003317 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003318 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003319 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003320 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003321
Eliad Peller87fbcb02011-10-05 11:55:41 +02003322 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003323 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003324 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003325 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003326 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003327
Eliad Peller784f6942011-10-05 11:55:39 +02003328 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003329 if (ret < 0)
3330 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003331 }
3332
Arik Nemtsove78a2872010-10-16 19:07:21 +02003333 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3334 if (ret < 0)
3335 goto out;
3336
3337 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3338 if (bss_conf->enable_beacon) {
3339 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003340 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003341 if (ret < 0)
3342 goto out;
3343
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003344 ret = wl1271_ap_init_hwenc(wl);
3345 if (ret < 0)
3346 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003347
3348 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3349 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003350 }
3351 } else {
3352 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003353 ret = wl12xx_cmd_role_stop_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003354 if (ret < 0)
3355 goto out;
3356
3357 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3358 wl1271_debug(DEBUG_AP, "stopped AP");
3359 }
3360 }
3361 }
3362
3363 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3364 if (ret < 0)
3365 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003366
3367 /* Handle HT information change */
3368 if ((changed & BSS_CHANGED_HT) &&
3369 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3370 ret = wl1271_acx_set_ht_information(wl,
3371 bss_conf->ht_operation_mode);
3372 if (ret < 0) {
3373 wl1271_warning("Set ht information failed %d", ret);
3374 goto out;
3375 }
3376 }
3377
Arik Nemtsove78a2872010-10-16 19:07:21 +02003378out:
3379 return;
3380}
3381
3382/* STA/IBSS mode changes */
3383static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3384 struct ieee80211_vif *vif,
3385 struct ieee80211_bss_conf *bss_conf,
3386 u32 changed)
3387{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003388 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003389 bool do_join = false, set_assoc = false;
3390 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003391 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003392 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003393 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003394 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003395 bool sta_exists = false;
3396 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003397
3398 if (is_ibss) {
3399 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3400 changed);
3401 if (ret < 0)
3402 goto out;
3403 }
3404
Eliad Peller227e81e2011-08-14 13:17:26 +03003405 if (changed & BSS_CHANGED_IBSS) {
3406 if (bss_conf->ibss_joined) {
3407 set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
3408 ibss_joined = true;
3409 } else {
3410 if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
3411 &wl->flags)) {
3412 wl1271_unjoin(wl);
3413 wl12xx_cmd_role_start_dev(wl);
3414 wl12xx_roc(wl, wl->dev_role_id);
3415 }
3416 }
3417 }
3418
3419 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003420 do_join = true;
3421
3422 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003423 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003424 do_join = true;
3425
Eliad Peller227e81e2011-08-14 13:17:26 +03003426 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003427 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3428 bss_conf->enable_beacon ? "enabled" : "disabled");
3429
3430 if (bss_conf->enable_beacon)
3431 wl->set_bss_type = BSS_TYPE_IBSS;
3432 else
3433 wl->set_bss_type = BSS_TYPE_STA_BSS;
3434 do_join = true;
3435 }
3436
Arik Nemtsove78a2872010-10-16 19:07:21 +02003437 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003438 bool enable = false;
3439 if (bss_conf->cqm_rssi_thold)
3440 enable = true;
3441 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3442 bss_conf->cqm_rssi_thold,
3443 bss_conf->cqm_rssi_hyst);
3444 if (ret < 0)
3445 goto out;
3446 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3447 }
3448
Eliad Pellercdf09492011-10-05 11:55:44 +02003449 if (changed & BSS_CHANGED_BSSID)
3450 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003451 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003452 if (ret < 0)
3453 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003454
Eliad Peller784f6942011-10-05 11:55:39 +02003455 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003456 if (ret < 0)
3457 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003458
Eliad Pellerfa287b82010-12-26 09:27:50 +01003459 /* Need to update the BSSID (for filtering etc) */
3460 do_join = true;
3461 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003462
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003463 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3464 rcu_read_lock();
3465 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3466 if (!sta)
3467 goto sta_not_found;
3468
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003469 /* save the supp_rates of the ap */
3470 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3471 if (sta->ht_cap.ht_supported)
3472 sta_rate_set |=
3473 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003474 sta_ht_cap = sta->ht_cap;
3475 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003476
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003477sta_not_found:
3478 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003479 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003480
Arik Nemtsove78a2872010-10-16 19:07:21 +02003481 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003482 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003483 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003484 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003485 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003486 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003487
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003488 wl->ps_poll_failures = 0;
3489
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003490 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003491 * use basic rates from AP, and determine lowest rate
3492 * to use with control frames.
3493 */
3494 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003495 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003496 wl1271_tx_enabled_rates_get(wl, rates,
3497 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003498 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003499 wl1271_tx_min_rate_get(wl,
3500 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003501 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003502 wlvif->rate_set =
3503 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003504 sta_rate_set,
3505 wl->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003506 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003507 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003508 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003509
3510 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003511 * with wl1271, we don't need to update the
3512 * beacon_int and dtim_period, because the firmware
3513 * updates it by itself when the first beacon is
3514 * received after a join.
3515 */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003516 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wl->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003517 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003518 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003519
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003520 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003521 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003522 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003523 dev_kfree_skb(wl->probereq);
3524 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3525 ieoffset = offsetof(struct ieee80211_mgmt,
3526 u.probe_req.variable);
3527 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003528
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003529 /* enable the connection monitoring feature */
3530 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003531 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003532 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003533 } else {
3534 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003535 bool was_assoc =
3536 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3537 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003538 bool was_ifup =
3539 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3540 &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003541 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003542
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003543 /* free probe-request template */
3544 dev_kfree_skb(wl->probereq);
3545 wl->probereq = NULL;
3546
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003547 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003548 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003549
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003550 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003551 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003552 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003553 wl1271_tx_min_rate_get(wl,
3554 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003555 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003556 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003557 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003558
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003559 /* disable connection monitor features */
3560 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003561
3562 /* Disable the keep-alive feature */
3563 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003564 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003565 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003566
3567 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003568 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003569 u32 conf_flags = wl->hw->conf.flags;
3570 /*
3571 * we might have to disable roc, if there was
3572 * no IF_OPER_UP notification.
3573 */
3574 if (!was_ifup) {
3575 ret = wl12xx_croc(wl, wl->role_id);
3576 if (ret < 0)
3577 goto out;
3578 }
3579 /*
3580 * (we also need to disable roc in case of
3581 * roaming on the same channel. until we will
3582 * have a better flow...)
3583 */
3584 if (test_bit(wl->dev_role_id, wl->roc_map)) {
3585 ret = wl12xx_croc(wl, wl->dev_role_id);
3586 if (ret < 0)
3587 goto out;
3588 }
3589
Eliad Peller30df14d2011-04-05 19:13:28 +03003590 wl1271_unjoin(wl);
Eliad Peller251c1772011-08-14 13:17:17 +03003591 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
3592 wl12xx_cmd_role_start_dev(wl);
3593 wl12xx_roc(wl, wl->dev_role_id);
3594 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003595 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003596 }
3597 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003598
Eliad Pellerd192d262011-05-24 14:33:08 +03003599 if (changed & BSS_CHANGED_IBSS) {
3600 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3601 bss_conf->ibss_joined);
3602
3603 if (bss_conf->ibss_joined) {
3604 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003605 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003606 wl1271_tx_enabled_rates_get(wl, rates,
3607 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003608 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003609 wl1271_tx_min_rate_get(wl,
3610 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003611
Shahar Levi06b660e2011-09-05 13:54:36 +03003612 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003613 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3614 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003615 if (ret < 0)
3616 goto out;
3617 }
3618 }
3619
Arik Nemtsove78a2872010-10-16 19:07:21 +02003620 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3621 if (ret < 0)
3622 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003623
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003624 if (changed & BSS_CHANGED_ARP_FILTER) {
3625 __be32 addr = bss_conf->arp_addr_list[0];
3626 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3627
Eliad Pellerc5312772010-12-09 11:31:27 +02003628 if (bss_conf->arp_addr_cnt == 1 &&
3629 bss_conf->arp_filter_enabled) {
3630 /*
3631 * The template should have been configured only upon
3632 * association. however, it seems that the correct ip
3633 * isn't being set (when sending), so we have to
3634 * reconfigure the template upon every ip change.
3635 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003636 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003637 if (ret < 0) {
3638 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003639 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003640 }
3641
3642 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003643 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003644 addr);
3645 } else
3646 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003647
3648 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003649 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003650 }
3651
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003652 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003653 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003654 if (ret < 0) {
3655 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003656 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003657 }
Eliad Peller251c1772011-08-14 13:17:17 +03003658
3659 /* ROC until connected (after EAPOL exchange) */
3660 if (!is_ibss) {
3661 ret = wl12xx_roc(wl, wl->role_id);
3662 if (ret < 0)
3663 goto out;
3664
3665 wl1271_check_operstate(wl,
3666 ieee80211_get_operstate(vif));
3667 }
3668 /*
3669 * stop device role if started (we might already be in
3670 * STA role). TODO: make it better.
3671 */
3672 if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3673 ret = wl12xx_croc(wl, wl->dev_role_id);
3674 if (ret < 0)
3675 goto out;
3676
3677 ret = wl12xx_cmd_role_stop_dev(wl);
3678 if (ret < 0)
3679 goto out;
3680 }
Eliad Peller05dba352011-08-23 16:37:01 +03003681
3682 /* If we want to go in PSM but we're not there yet */
3683 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3684 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
3685 enum wl1271_cmd_ps_mode mode;
3686
3687 mode = STATION_POWER_SAVE_MODE;
3688 ret = wl1271_ps_set_mode(wl, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003689 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003690 true);
3691 if (ret < 0)
3692 goto out;
3693 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003694 }
3695
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003696 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003697 if (sta_exists) {
3698 if ((changed & BSS_CHANGED_HT) &&
3699 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003700 ret = wl1271_acx_set_ht_capabilities(wl,
3701 &sta_ht_cap,
3702 true,
3703 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003704 if (ret < 0) {
3705 wl1271_warning("Set ht cap true failed %d",
3706 ret);
3707 goto out;
3708 }
3709 }
3710 /* handle new association without HT and disassociation */
3711 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003712 ret = wl1271_acx_set_ht_capabilities(wl,
3713 &sta_ht_cap,
3714 false,
3715 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003716 if (ret < 0) {
3717 wl1271_warning("Set ht cap false failed %d",
3718 ret);
3719 goto out;
3720 }
3721 }
3722 }
3723
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003724 /* Handle HT information change. Done after join. */
3725 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003726 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3727 ret = wl1271_acx_set_ht_information(wl,
3728 bss_conf->ht_operation_mode);
3729 if (ret < 0) {
3730 wl1271_warning("Set ht information failed %d", ret);
3731 goto out;
3732 }
3733 }
3734
Arik Nemtsove78a2872010-10-16 19:07:21 +02003735out:
3736 return;
3737}
3738
3739static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3740 struct ieee80211_vif *vif,
3741 struct ieee80211_bss_conf *bss_conf,
3742 u32 changed)
3743{
3744 struct wl1271 *wl = hw->priv;
3745 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3746 int ret;
3747
3748 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3749 (int)changed);
3750
3751 mutex_lock(&wl->mutex);
3752
3753 if (unlikely(wl->state == WL1271_STATE_OFF))
3754 goto out;
3755
Ido Yariva6208652011-03-01 15:14:41 +02003756 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003757 if (ret < 0)
3758 goto out;
3759
3760 if (is_ap)
3761 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3762 else
3763 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3764
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003765 wl1271_ps_elp_sleep(wl);
3766
3767out:
3768 mutex_unlock(&wl->mutex);
3769}
3770
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003771static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3772 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003773 const struct ieee80211_tx_queue_params *params)
3774{
3775 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003776 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003777 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003778
3779 mutex_lock(&wl->mutex);
3780
3781 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3782
Kalle Valo4695dc92010-03-18 12:26:38 +02003783 if (params->uapsd)
3784 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3785 else
3786 ps_scheme = CONF_PS_SCHEME_LEGACY;
3787
Arik Nemtsov488fc542010-10-16 20:33:45 +02003788 if (wl->state == WL1271_STATE_OFF) {
3789 /*
3790 * If the state is off, the parameters will be recorded and
3791 * configured on init. This happens in AP-mode.
3792 */
3793 struct conf_tx_ac_category *conf_ac =
3794 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3795 struct conf_tx_tid *conf_tid =
3796 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3797
3798 conf_ac->ac = wl1271_tx_get_queue(queue);
3799 conf_ac->cw_min = (u8)params->cw_min;
3800 conf_ac->cw_max = params->cw_max;
3801 conf_ac->aifsn = params->aifs;
3802 conf_ac->tx_op_limit = params->txop << 5;
3803
3804 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3805 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3806 conf_tid->tsid = wl1271_tx_get_queue(queue);
3807 conf_tid->ps_scheme = ps_scheme;
3808 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3809 conf_tid->apsd_conf[0] = 0;
3810 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003811 goto out;
3812 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003813
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003814 ret = wl1271_ps_elp_wakeup(wl);
3815 if (ret < 0)
3816 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003817
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003818 /*
3819 * the txop is confed in units of 32us by the mac80211,
3820 * we need us
3821 */
3822 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3823 params->cw_min, params->cw_max,
3824 params->aifs, params->txop << 5);
3825 if (ret < 0)
3826 goto out_sleep;
3827
3828 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3829 CONF_CHANNEL_TYPE_EDCF,
3830 wl1271_tx_get_queue(queue),
3831 ps_scheme, CONF_ACK_POLICY_LEGACY,
3832 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003833
3834out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003835 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003836
3837out:
3838 mutex_unlock(&wl->mutex);
3839
3840 return ret;
3841}
3842
Eliad Peller37a41b42011-09-21 14:06:11 +03003843static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
3844 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003845{
3846
3847 struct wl1271 *wl = hw->priv;
3848 u64 mactime = ULLONG_MAX;
3849 int ret;
3850
3851 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3852
3853 mutex_lock(&wl->mutex);
3854
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003855 if (unlikely(wl->state == WL1271_STATE_OFF))
3856 goto out;
3857
Ido Yariva6208652011-03-01 15:14:41 +02003858 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003859 if (ret < 0)
3860 goto out;
3861
3862 ret = wl1271_acx_tsf_info(wl, &mactime);
3863 if (ret < 0)
3864 goto out_sleep;
3865
3866out_sleep:
3867 wl1271_ps_elp_sleep(wl);
3868
3869out:
3870 mutex_unlock(&wl->mutex);
3871 return mactime;
3872}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003873
John W. Linvilleece550d2010-07-28 16:41:06 -04003874static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3875 struct survey_info *survey)
3876{
3877 struct wl1271 *wl = hw->priv;
3878 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003879
John W. Linvilleece550d2010-07-28 16:41:06 -04003880 if (idx != 0)
3881 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003882
John W. Linvilleece550d2010-07-28 16:41:06 -04003883 survey->channel = conf->channel;
3884 survey->filled = SURVEY_INFO_NOISE_DBM;
3885 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003886
John W. Linvilleece550d2010-07-28 16:41:06 -04003887 return 0;
3888}
3889
Arik Nemtsov409622e2011-02-23 00:22:29 +02003890static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003891 struct ieee80211_sta *sta,
3892 u8 *hlid)
3893{
3894 struct wl1271_station *wl_sta;
3895 int id;
3896
3897 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3898 if (id >= AP_MAX_STATIONS) {
3899 wl1271_warning("could not allocate HLID - too much stations");
3900 return -EBUSY;
3901 }
3902
3903 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsov04216da2011-08-14 13:17:38 +03003904 set_bit(id, wl->ap_hlid_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003905 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3906 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003907 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03003908 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003909 return 0;
3910}
3911
Arik Nemtsovf1acea92011-08-25 12:43:17 +03003912void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003913{
3914 int id = hlid - WL1271_AP_STA_HLID_START;
3915
Arik Nemtsovf1acea92011-08-25 12:43:17 +03003916 if (hlid < WL1271_AP_STA_HLID_START)
3917 return;
3918
3919 if (!test_bit(id, wl->ap_hlid_map))
Arik Nemtsov409622e2011-02-23 00:22:29 +02003920 return;
3921
Arik Nemtsov04216da2011-08-14 13:17:38 +03003922 clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003923 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003924 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003925 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003926 __clear_bit(hlid, &wl->ap_ps_map);
3927 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +03003928 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003929}
3930
3931static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3932 struct ieee80211_vif *vif,
3933 struct ieee80211_sta *sta)
3934{
3935 struct wl1271 *wl = hw->priv;
3936 int ret = 0;
3937 u8 hlid;
3938
3939 mutex_lock(&wl->mutex);
3940
3941 if (unlikely(wl->state == WL1271_STATE_OFF))
3942 goto out;
3943
3944 if (wl->bss_type != BSS_TYPE_AP_BSS)
3945 goto out;
3946
3947 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3948
Arik Nemtsov409622e2011-02-23 00:22:29 +02003949 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003950 if (ret < 0)
3951 goto out;
3952
Ido Yariva6208652011-03-01 15:14:41 +02003953 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003954 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003955 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003956
Eliad Pellerc690ec82011-08-14 13:17:07 +03003957 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003958 if (ret < 0)
3959 goto out_sleep;
3960
Eliad Pellerb67476e2011-08-14 13:17:23 +03003961 ret = wl12xx_cmd_set_peer_state(wl, hlid);
3962 if (ret < 0)
3963 goto out_sleep;
3964
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003965 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
3966 if (ret < 0)
3967 goto out_sleep;
3968
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003969out_sleep:
3970 wl1271_ps_elp_sleep(wl);
3971
Arik Nemtsov409622e2011-02-23 00:22:29 +02003972out_free_sta:
3973 if (ret < 0)
3974 wl1271_free_sta(wl, hlid);
3975
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003976out:
3977 mutex_unlock(&wl->mutex);
3978 return ret;
3979}
3980
3981static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3982 struct ieee80211_vif *vif,
3983 struct ieee80211_sta *sta)
3984{
3985 struct wl1271 *wl = hw->priv;
3986 struct wl1271_station *wl_sta;
3987 int ret = 0, id;
3988
3989 mutex_lock(&wl->mutex);
3990
3991 if (unlikely(wl->state == WL1271_STATE_OFF))
3992 goto out;
3993
3994 if (wl->bss_type != BSS_TYPE_AP_BSS)
3995 goto out;
3996
3997 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3998
3999 wl_sta = (struct wl1271_station *)sta->drv_priv;
4000 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
4001 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
4002 goto out;
4003
Ido Yariva6208652011-03-01 15:14:41 +02004004 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004005 if (ret < 0)
4006 goto out;
4007
Eliad Pellerc690ec82011-08-14 13:17:07 +03004008 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004009 if (ret < 0)
4010 goto out_sleep;
4011
Arik Nemtsov409622e2011-02-23 00:22:29 +02004012 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004013
4014out_sleep:
4015 wl1271_ps_elp_sleep(wl);
4016
4017out:
4018 mutex_unlock(&wl->mutex);
4019 return ret;
4020}
4021
Luciano Coelho4623ec72011-03-21 19:26:41 +02004022static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4023 struct ieee80211_vif *vif,
4024 enum ieee80211_ampdu_mlme_action action,
4025 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4026 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004027{
4028 struct wl1271 *wl = hw->priv;
4029 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004030 u8 hlid, *ba_bitmap;
4031
4032 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4033 tid);
4034
4035 /* sanity check - the fields in FW are only 8bits wide */
4036 if (WARN_ON(tid > 0xFF))
4037 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004038
4039 mutex_lock(&wl->mutex);
4040
4041 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4042 ret = -EAGAIN;
4043 goto out;
4044 }
4045
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004046 if (wl->bss_type == BSS_TYPE_STA_BSS) {
4047 hlid = wl->sta_hlid;
4048 ba_bitmap = &wl->ba_rx_bitmap;
4049 } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
4050 struct wl1271_station *wl_sta;
4051
4052 wl_sta = (struct wl1271_station *)sta->drv_priv;
4053 hlid = wl_sta->hlid;
4054 ba_bitmap = &wl->links[hlid].ba_bitmap;
4055 } else {
4056 ret = -EINVAL;
4057 goto out;
4058 }
4059
Ido Yariva6208652011-03-01 15:14:41 +02004060 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004061 if (ret < 0)
4062 goto out;
4063
Shahar Levi70559a02011-05-22 16:10:22 +03004064 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4065 tid, action);
4066
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004067 switch (action) {
4068 case IEEE80211_AMPDU_RX_START:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004069 if (!wl->ba_support || !wl->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004070 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004071 break;
4072 }
4073
4074 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4075 ret = -EBUSY;
4076 wl1271_error("exceeded max RX BA sessions");
4077 break;
4078 }
4079
4080 if (*ba_bitmap & BIT(tid)) {
4081 ret = -EINVAL;
4082 wl1271_error("cannot enable RX BA session on active "
4083 "tid: %d", tid);
4084 break;
4085 }
4086
4087 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4088 hlid);
4089 if (!ret) {
4090 *ba_bitmap |= BIT(tid);
4091 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004092 }
4093 break;
4094
4095 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004096 if (!(*ba_bitmap & BIT(tid))) {
4097 ret = -EINVAL;
4098 wl1271_error("no active RX BA session on tid: %d",
4099 tid);
4100 break;
4101 }
4102
4103 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4104 hlid);
4105 if (!ret) {
4106 *ba_bitmap &= ~BIT(tid);
4107 wl->ba_rx_session_count--;
4108 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004109 break;
4110
4111 /*
4112 * The BA initiator session management in FW independently.
4113 * Falling break here on purpose for all TX APDU commands.
4114 */
4115 case IEEE80211_AMPDU_TX_START:
4116 case IEEE80211_AMPDU_TX_STOP:
4117 case IEEE80211_AMPDU_TX_OPERATIONAL:
4118 ret = -EINVAL;
4119 break;
4120
4121 default:
4122 wl1271_error("Incorrect ampdu action id=%x\n", action);
4123 ret = -EINVAL;
4124 }
4125
4126 wl1271_ps_elp_sleep(wl);
4127
4128out:
4129 mutex_unlock(&wl->mutex);
4130
4131 return ret;
4132}
4133
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004134static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4135 struct ieee80211_vif *vif,
4136 const struct cfg80211_bitrate_mask *mask)
4137{
4138 struct wl1271 *wl = hw->priv;
4139 int i;
4140
4141 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4142 mask->control[NL80211_BAND_2GHZ].legacy,
4143 mask->control[NL80211_BAND_5GHZ].legacy);
4144
4145 mutex_lock(&wl->mutex);
4146
4147 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
4148 wl->bitrate_masks[i] =
4149 wl1271_tx_enabled_rates_get(wl,
4150 mask->control[i].legacy,
4151 i);
4152 mutex_unlock(&wl->mutex);
4153
4154 return 0;
4155}
4156
Shahar Levi6d158ff2011-09-08 13:01:33 +03004157static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4158 struct ieee80211_channel_switch *ch_switch)
4159{
4160 struct wl1271 *wl = hw->priv;
4161 int ret;
4162
4163 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4164
4165 mutex_lock(&wl->mutex);
4166
4167 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4168 mutex_unlock(&wl->mutex);
4169 ieee80211_chswitch_done(wl->vif, false);
4170 return;
4171 }
4172
4173 ret = wl1271_ps_elp_wakeup(wl);
4174 if (ret < 0)
4175 goto out;
4176
4177 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
4178
4179 if (!ret)
4180 set_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags);
4181
4182 wl1271_ps_elp_sleep(wl);
4183
4184out:
4185 mutex_unlock(&wl->mutex);
4186}
4187
Arik Nemtsov33437892011-04-26 23:35:39 +03004188static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4189{
4190 struct wl1271 *wl = hw->priv;
4191 bool ret = false;
4192
4193 mutex_lock(&wl->mutex);
4194
4195 if (unlikely(wl->state == WL1271_STATE_OFF))
4196 goto out;
4197
4198 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004199 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004200
4201 /* the above is appropriate for STA mode for PS purposes */
4202 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
4203
4204out:
4205 mutex_unlock(&wl->mutex);
4206
4207 return ret;
4208}
4209
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004210/* can't be const, mac80211 writes to this */
4211static struct ieee80211_rate wl1271_rates[] = {
4212 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004213 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4214 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004215 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004216 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4217 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004218 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4219 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004220 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4221 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004222 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4223 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004224 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4225 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004226 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4227 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004228 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4229 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004230 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004231 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4232 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004233 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004234 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4235 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004236 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004237 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4238 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004239 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004240 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4241 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004242 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004243 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4244 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004245 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004246 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4247 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004248 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004249 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4250 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004251};
4252
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004253/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004254static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004255 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004256 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004257 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4258 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4259 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004260 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004261 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4262 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4263 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004264 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004265 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4266 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4267 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004268 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004269};
4270
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004271/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004272static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004273 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004274 7, /* CONF_HW_RXTX_RATE_MCS7 */
4275 6, /* CONF_HW_RXTX_RATE_MCS6 */
4276 5, /* CONF_HW_RXTX_RATE_MCS5 */
4277 4, /* CONF_HW_RXTX_RATE_MCS4 */
4278 3, /* CONF_HW_RXTX_RATE_MCS3 */
4279 2, /* CONF_HW_RXTX_RATE_MCS2 */
4280 1, /* CONF_HW_RXTX_RATE_MCS1 */
4281 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004282
4283 11, /* CONF_HW_RXTX_RATE_54 */
4284 10, /* CONF_HW_RXTX_RATE_48 */
4285 9, /* CONF_HW_RXTX_RATE_36 */
4286 8, /* CONF_HW_RXTX_RATE_24 */
4287
4288 /* TI-specific rate */
4289 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4290
4291 7, /* CONF_HW_RXTX_RATE_18 */
4292 6, /* CONF_HW_RXTX_RATE_12 */
4293 3, /* CONF_HW_RXTX_RATE_11 */
4294 5, /* CONF_HW_RXTX_RATE_9 */
4295 4, /* CONF_HW_RXTX_RATE_6 */
4296 2, /* CONF_HW_RXTX_RATE_5_5 */
4297 1, /* CONF_HW_RXTX_RATE_2 */
4298 0 /* CONF_HW_RXTX_RATE_1 */
4299};
4300
Shahar Levie8b03a22010-10-13 16:09:39 +02004301/* 11n STA capabilities */
4302#define HW_RX_HIGHEST_RATE 72
4303
Shahar Levi00d20102010-11-08 11:20:10 +00004304#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004305 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4306 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004307 .ht_supported = true, \
4308 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4309 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4310 .mcs = { \
4311 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4312 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4313 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4314 }, \
4315}
4316
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004317/* can't be const, mac80211 writes to this */
4318static struct ieee80211_supported_band wl1271_band_2ghz = {
4319 .channels = wl1271_channels,
4320 .n_channels = ARRAY_SIZE(wl1271_channels),
4321 .bitrates = wl1271_rates,
4322 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004323 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004324};
4325
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004326/* 5 GHz data rates for WL1273 */
4327static struct ieee80211_rate wl1271_rates_5ghz[] = {
4328 { .bitrate = 60,
4329 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4330 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4331 { .bitrate = 90,
4332 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4333 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4334 { .bitrate = 120,
4335 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4336 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4337 { .bitrate = 180,
4338 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4339 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4340 { .bitrate = 240,
4341 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4342 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4343 { .bitrate = 360,
4344 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4345 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4346 { .bitrate = 480,
4347 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4348 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4349 { .bitrate = 540,
4350 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4351 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4352};
4353
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004354/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004355static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004356 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4357 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4358 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4359 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4360 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4361 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4362 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4363 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4364 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4365 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4366 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4367 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4368 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4369 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4370 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4371 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4372 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4373 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4374 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4375 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4376 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4377 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4378 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4379 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4380 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4381 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4382 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4383 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4384 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4385 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4386 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4387 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4388 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4389 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004390};
4391
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004392/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004393static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004394 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004395 7, /* CONF_HW_RXTX_RATE_MCS7 */
4396 6, /* CONF_HW_RXTX_RATE_MCS6 */
4397 5, /* CONF_HW_RXTX_RATE_MCS5 */
4398 4, /* CONF_HW_RXTX_RATE_MCS4 */
4399 3, /* CONF_HW_RXTX_RATE_MCS3 */
4400 2, /* CONF_HW_RXTX_RATE_MCS2 */
4401 1, /* CONF_HW_RXTX_RATE_MCS1 */
4402 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004403
4404 7, /* CONF_HW_RXTX_RATE_54 */
4405 6, /* CONF_HW_RXTX_RATE_48 */
4406 5, /* CONF_HW_RXTX_RATE_36 */
4407 4, /* CONF_HW_RXTX_RATE_24 */
4408
4409 /* TI-specific rate */
4410 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4411
4412 3, /* CONF_HW_RXTX_RATE_18 */
4413 2, /* CONF_HW_RXTX_RATE_12 */
4414 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4415 1, /* CONF_HW_RXTX_RATE_9 */
4416 0, /* CONF_HW_RXTX_RATE_6 */
4417 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4418 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4419 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4420};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004421
4422static struct ieee80211_supported_band wl1271_band_5ghz = {
4423 .channels = wl1271_channels_5ghz,
4424 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4425 .bitrates = wl1271_rates_5ghz,
4426 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004427 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004428};
4429
Tobias Klausera0ea9492010-05-20 10:38:11 +02004430static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004431 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4432 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4433};
4434
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004435static const struct ieee80211_ops wl1271_ops = {
4436 .start = wl1271_op_start,
4437 .stop = wl1271_op_stop,
4438 .add_interface = wl1271_op_add_interface,
4439 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004440#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004441 .suspend = wl1271_op_suspend,
4442 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004443#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004444 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004445 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004446 .configure_filter = wl1271_op_configure_filter,
4447 .tx = wl1271_op_tx,
4448 .set_key = wl1271_op_set_key,
4449 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004450 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004451 .sched_scan_start = wl1271_op_sched_scan_start,
4452 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004453 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004454 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004455 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004456 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004457 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004458 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004459 .sta_add = wl1271_op_sta_add,
4460 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004461 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004462 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004463 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004464 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004465 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004466};
4467
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004468
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004469u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004470{
4471 u8 idx;
4472
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004473 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004474
4475 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4476 wl1271_error("Illegal RX rate from HW: %d", rate);
4477 return 0;
4478 }
4479
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004480 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004481 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4482 wl1271_error("Unsupported RX rate from HW: %d", rate);
4483 return 0;
4484 }
4485
4486 return idx;
4487}
4488
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004489static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4490 struct device_attribute *attr,
4491 char *buf)
4492{
4493 struct wl1271 *wl = dev_get_drvdata(dev);
4494 ssize_t len;
4495
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004496 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004497
4498 mutex_lock(&wl->mutex);
4499 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4500 wl->sg_enabled);
4501 mutex_unlock(&wl->mutex);
4502
4503 return len;
4504
4505}
4506
4507static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4508 struct device_attribute *attr,
4509 const char *buf, size_t count)
4510{
4511 struct wl1271 *wl = dev_get_drvdata(dev);
4512 unsigned long res;
4513 int ret;
4514
Luciano Coelho6277ed62011-04-01 17:49:54 +03004515 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004516 if (ret < 0) {
4517 wl1271_warning("incorrect value written to bt_coex_mode");
4518 return count;
4519 }
4520
4521 mutex_lock(&wl->mutex);
4522
4523 res = !!res;
4524
4525 if (res == wl->sg_enabled)
4526 goto out;
4527
4528 wl->sg_enabled = res;
4529
4530 if (wl->state == WL1271_STATE_OFF)
4531 goto out;
4532
Ido Yariva6208652011-03-01 15:14:41 +02004533 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004534 if (ret < 0)
4535 goto out;
4536
4537 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4538 wl1271_ps_elp_sleep(wl);
4539
4540 out:
4541 mutex_unlock(&wl->mutex);
4542 return count;
4543}
4544
4545static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4546 wl1271_sysfs_show_bt_coex_state,
4547 wl1271_sysfs_store_bt_coex_state);
4548
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004549static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4550 struct device_attribute *attr,
4551 char *buf)
4552{
4553 struct wl1271 *wl = dev_get_drvdata(dev);
4554 ssize_t len;
4555
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004556 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004557
4558 mutex_lock(&wl->mutex);
4559 if (wl->hw_pg_ver >= 0)
4560 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4561 else
4562 len = snprintf(buf, len, "n/a\n");
4563 mutex_unlock(&wl->mutex);
4564
4565 return len;
4566}
4567
Gery Kahn6f07b722011-07-18 14:21:49 +03004568static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004569 wl1271_sysfs_show_hw_pg_ver, NULL);
4570
Ido Yariv95dac04f2011-06-06 14:57:06 +03004571static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4572 struct bin_attribute *bin_attr,
4573 char *buffer, loff_t pos, size_t count)
4574{
4575 struct device *dev = container_of(kobj, struct device, kobj);
4576 struct wl1271 *wl = dev_get_drvdata(dev);
4577 ssize_t len;
4578 int ret;
4579
4580 ret = mutex_lock_interruptible(&wl->mutex);
4581 if (ret < 0)
4582 return -ERESTARTSYS;
4583
4584 /* Let only one thread read the log at a time, blocking others */
4585 while (wl->fwlog_size == 0) {
4586 DEFINE_WAIT(wait);
4587
4588 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4589 &wait,
4590 TASK_INTERRUPTIBLE);
4591
4592 if (wl->fwlog_size != 0) {
4593 finish_wait(&wl->fwlog_waitq, &wait);
4594 break;
4595 }
4596
4597 mutex_unlock(&wl->mutex);
4598
4599 schedule();
4600 finish_wait(&wl->fwlog_waitq, &wait);
4601
4602 if (signal_pending(current))
4603 return -ERESTARTSYS;
4604
4605 ret = mutex_lock_interruptible(&wl->mutex);
4606 if (ret < 0)
4607 return -ERESTARTSYS;
4608 }
4609
4610 /* Check if the fwlog is still valid */
4611 if (wl->fwlog_size < 0) {
4612 mutex_unlock(&wl->mutex);
4613 return 0;
4614 }
4615
4616 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4617 len = min(count, (size_t)wl->fwlog_size);
4618 wl->fwlog_size -= len;
4619 memcpy(buffer, wl->fwlog, len);
4620
4621 /* Make room for new messages */
4622 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4623
4624 mutex_unlock(&wl->mutex);
4625
4626 return len;
4627}
4628
4629static struct bin_attribute fwlog_attr = {
4630 .attr = {.name = "fwlog", .mode = S_IRUSR},
4631 .read = wl1271_sysfs_read_fwlog,
4632};
4633
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004634int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004635{
4636 int ret;
4637
4638 if (wl->mac80211_registered)
4639 return 0;
4640
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004641 ret = wl1271_fetch_nvs(wl);
4642 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004643 /* NOTE: The wl->nvs->nvs element must be first, in
4644 * order to simplify the casting, we assume it is at
4645 * the beginning of the wl->nvs structure.
4646 */
4647 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004648
4649 wl->mac_addr[0] = nvs_ptr[11];
4650 wl->mac_addr[1] = nvs_ptr[10];
4651 wl->mac_addr[2] = nvs_ptr[6];
4652 wl->mac_addr[3] = nvs_ptr[5];
4653 wl->mac_addr[4] = nvs_ptr[4];
4654 wl->mac_addr[5] = nvs_ptr[3];
4655 }
4656
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004657 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4658
4659 ret = ieee80211_register_hw(wl->hw);
4660 if (ret < 0) {
4661 wl1271_error("unable to register mac80211 hw: %d", ret);
4662 return ret;
4663 }
4664
4665 wl->mac80211_registered = true;
4666
Eliad Pellerd60080a2010-11-24 12:53:16 +02004667 wl1271_debugfs_init(wl);
4668
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004669 register_netdevice_notifier(&wl1271_dev_notifier);
4670
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004671 wl1271_notice("loaded");
4672
4673 return 0;
4674}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004675EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004676
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004677void wl1271_unregister_hw(struct wl1271 *wl)
4678{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004679 if (wl->state == WL1271_STATE_PLT)
4680 __wl1271_plt_stop(wl);
4681
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004682 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004683 ieee80211_unregister_hw(wl->hw);
4684 wl->mac80211_registered = false;
4685
4686}
4687EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4688
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004689int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004690{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004691 static const u32 cipher_suites[] = {
4692 WLAN_CIPHER_SUITE_WEP40,
4693 WLAN_CIPHER_SUITE_WEP104,
4694 WLAN_CIPHER_SUITE_TKIP,
4695 WLAN_CIPHER_SUITE_CCMP,
4696 WL1271_CIPHER_SUITE_GEM,
4697 };
4698
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004699 /* The tx descriptor buffer and the TKIP space. */
4700 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4701 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004702
4703 /* unit us */
4704 /* FIXME: find a proper value */
4705 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004706 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004707
4708 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004709 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004710 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004711 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004712 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004713 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004714 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004715 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004716 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004717 IEEE80211_HW_AP_LINK_PS |
4718 IEEE80211_HW_AMPDU_AGGREGATION |
4719 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004720
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004721 wl->hw->wiphy->cipher_suites = cipher_suites;
4722 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4723
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004724 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004725 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4726 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004727 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004728 wl->hw->wiphy->max_sched_scan_ssids = 16;
4729 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004730 /*
4731 * Maximum length of elements in scanning probe request templates
4732 * should be the maximum length possible for a template, without
4733 * the IEEE80211 header of the template
4734 */
Eliad Peller154037d2011-08-14 13:17:12 +03004735 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004736 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004737
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004738 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4739 sizeof(struct ieee80211_header);
4740
Eliad Peller1ec23f72011-08-25 14:26:54 +03004741 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4742
Luciano Coelho4a31c112011-03-21 23:16:14 +02004743 /* make sure all our channels fit in the scanned_ch bitmask */
4744 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4745 ARRAY_SIZE(wl1271_channels_5ghz) >
4746 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004747 /*
4748 * We keep local copies of the band structs because we need to
4749 * modify them on a per-device basis.
4750 */
4751 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4752 sizeof(wl1271_band_2ghz));
4753 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4754 sizeof(wl1271_band_5ghz));
4755
4756 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4757 &wl->bands[IEEE80211_BAND_2GHZ];
4758 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4759 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004760
Kalle Valo12bd8942010-03-18 12:26:33 +02004761 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004762 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004763
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004764 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4765
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004766 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004767
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004768 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004769 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004770
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004771 wl->hw->max_rx_aggregation_subframes = 8;
4772
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004773 return 0;
4774}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004775EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004776
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004777#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004778
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004779struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004780{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004781 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004782 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004783 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004784 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004785 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004786
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004787 BUILD_BUG_ON(AP_MAX_LINKS > WL12XX_MAX_LINKS);
4788
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004789 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4790 if (!hw) {
4791 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004792 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004793 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004794 }
4795
Julia Lawall929ebd32010-05-15 23:16:39 +02004796 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004797 if (!plat_dev) {
4798 wl1271_error("could not allocate platform_device");
4799 ret = -ENOMEM;
4800 goto err_plat_alloc;
4801 }
4802
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004803 wl = hw->priv;
4804 memset(wl, 0, sizeof(*wl));
4805
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004806 INIT_LIST_HEAD(&wl->list);
4807
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004808 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004809 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004810
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004811 for (i = 0; i < NUM_TX_QUEUES; i++)
4812 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004813
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004814 for (i = 0; i < NUM_TX_QUEUES; i++)
4815 for (j = 0; j < AP_MAX_LINKS; j++)
4816 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4817
Ido Yariva6208652011-03-01 15:14:41 +02004818 skb_queue_head_init(&wl->deferred_rx_queue);
4819 skb_queue_head_init(&wl->deferred_tx_queue);
4820
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004821 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004822 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004823 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004824 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4825 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4826 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004827 INIT_WORK(&wl->rx_streaming_enable_work,
4828 wl1271_rx_streaming_enable_work);
4829 INIT_WORK(&wl->rx_streaming_disable_work,
4830 wl1271_rx_streaming_disable_work);
4831
Eliad Peller92ef8962011-06-07 12:50:46 +03004832 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4833 if (!wl->freezable_wq) {
4834 ret = -ENOMEM;
4835 goto err_hw;
4836 }
4837
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004838 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004839 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004840 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004841 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004842 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004843 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004844 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004845 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004846 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004847 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004848 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004849 wl->bss_type = MAX_BSS_TYPE;
4850 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004851 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004852 wl->ap_ps_map = 0;
4853 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004854 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004855 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004856 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004857 wl->tx_security_seq = 0;
4858 wl->tx_security_last_seq_lsb = 0;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03004859 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Peller7f0979882011-08-14 13:17:06 +03004860 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004861 wl->system_hlid = WL12XX_SYSTEM_HLID;
Eliad Peller7f0979882011-08-14 13:17:06 +03004862 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004863 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4864 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsov712e9bf2011-08-14 13:17:20 +03004865 wl->session_counter = 0;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03004866 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
4867 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsovda032092011-08-25 12:43:15 +03004868 wl->active_sta_count = 0;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004869 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4870 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004871 wl->fwlog_size = 0;
4872 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004873
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004874 /* The system link is always allocated */
4875 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4876
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004877 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004878 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004879 wl->tx_frames[i] = NULL;
4880
4881 spin_lock_init(&wl->wl_lock);
4882
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004883 wl->state = WL1271_STATE_OFF;
4884 mutex_init(&wl->mutex);
4885
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004886 /* Apply default driver configuration. */
4887 wl1271_conf_init(wl);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004888 wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
4889 wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004890
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004891 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4892 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4893 if (!wl->aggr_buf) {
4894 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004895 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004896 }
4897
Ido Yariv990f5de2011-03-31 10:06:59 +02004898 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4899 if (!wl->dummy_packet) {
4900 ret = -ENOMEM;
4901 goto err_aggr;
4902 }
4903
Ido Yariv95dac04f2011-06-06 14:57:06 +03004904 /* Allocate one page for the FW log */
4905 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4906 if (!wl->fwlog) {
4907 ret = -ENOMEM;
4908 goto err_dummy_packet;
4909 }
4910
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004911 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004912 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004913 if (ret) {
4914 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004915 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004916 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004917 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004918
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004919 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004920 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004921 if (ret < 0) {
4922 wl1271_error("failed to create sysfs file bt_coex_state");
4923 goto err_platform;
4924 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004925
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004926 /* Create sysfs file to get HW PG version */
4927 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4928 if (ret < 0) {
4929 wl1271_error("failed to create sysfs file hw_pg_ver");
4930 goto err_bt_coex_state;
4931 }
4932
Ido Yariv95dac04f2011-06-06 14:57:06 +03004933 /* Create sysfs file for the FW log */
4934 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4935 if (ret < 0) {
4936 wl1271_error("failed to create sysfs file fwlog");
4937 goto err_hw_pg_ver;
4938 }
4939
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004940 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004941
Ido Yariv95dac04f2011-06-06 14:57:06 +03004942err_hw_pg_ver:
4943 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4944
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004945err_bt_coex_state:
4946 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4947
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004948err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004949 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004950
Ido Yariv95dac04f2011-06-06 14:57:06 +03004951err_fwlog:
4952 free_page((unsigned long)wl->fwlog);
4953
Ido Yariv990f5de2011-03-31 10:06:59 +02004954err_dummy_packet:
4955 dev_kfree_skb(wl->dummy_packet);
4956
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004957err_aggr:
4958 free_pages((unsigned long)wl->aggr_buf, order);
4959
Eliad Peller92ef8962011-06-07 12:50:46 +03004960err_wq:
4961 destroy_workqueue(wl->freezable_wq);
4962
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004963err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004964 wl1271_debugfs_exit(wl);
4965 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004966
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004967err_plat_alloc:
4968 ieee80211_free_hw(hw);
4969
4970err_hw_alloc:
4971
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004972 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004973}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004974EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004975
4976int wl1271_free_hw(struct wl1271 *wl)
4977{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004978 /* Unblock any fwlog readers */
4979 mutex_lock(&wl->mutex);
4980 wl->fwlog_size = -1;
4981 wake_up_interruptible_all(&wl->fwlog_waitq);
4982 mutex_unlock(&wl->mutex);
4983
4984 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004985
4986 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4987
4988 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004989 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004990 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02004991 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004992 free_pages((unsigned long)wl->aggr_buf,
4993 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004994 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004995
4996 wl1271_debugfs_exit(wl);
4997
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004998 vfree(wl->fw);
4999 wl->fw = NULL;
5000 kfree(wl->nvs);
5001 wl->nvs = NULL;
5002
5003 kfree(wl->fw_status);
5004 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005005 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005006
5007 ieee80211_free_hw(wl->hw);
5008
5009 return 0;
5010}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005011EXPORT_SYMBOL_GPL(wl1271_free_hw);
5012
Guy Eilam491bbd62011-01-12 10:33:29 +01005013u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005014EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005015module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005016MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5017
Ido Yariv95dac04f2011-06-06 14:57:06 +03005018module_param_named(fwlog, fwlog_param, charp, 0);
5019MODULE_PARM_DESC(keymap,
5020 "FW logger options: continuous, ondemand, dbgpins or disable");
5021
Eliad Peller2a5bff02011-08-25 18:10:59 +03005022module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5023MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5024
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005025MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005026MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005027MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");