blob: 5b13af0f8e8ecd02292719d305642fab681f6efe [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000038#include "reg.h"
39#include "io.h"
40#include "event.h"
41#include "tx.h"
42#include "rx.h"
43#include "ps.h"
44#include "init.h"
45#include "debugfs.h"
46#include "cmd.h"
47#include "boot.h"
48#include "testmode.h"
49#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030050
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020051#define WL1271_BOOT_RETRIES 3
52
Juuso Oikarinen8a080482009-10-13 12:47:44 +030053static struct conf_drv_settings default_conf = {
54 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030055 .params = {
56 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
57 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
58 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
61 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
62 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
64 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
65 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
66 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
68 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
69 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
70 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
71 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
73 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
74 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
75 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
76 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
77 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
78 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
79 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
82 /* active scan params */
83 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
84 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
85 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
86 /* passive scan params */
87 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
88 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
90 /* passive scan in dual antenna params */
91 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
92 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
93 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
94 /* general params */
95 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
96 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
97 [CONF_SG_BEACON_MISS_PERCENT] = 60,
98 [CONF_SG_DHCP_TIME] = 5000,
99 [CONF_SG_RXT] = 1200,
100 [CONF_SG_TXT] = 1000,
101 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
102 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
103 [CONF_SG_HV3_MAX_SERVED] = 6,
104 [CONF_SG_PS_POLL_TIMEOUT] = 10,
105 [CONF_SG_UPSD_TIMEOUT] = 10,
106 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
107 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
108 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
109 /* AP params */
110 [CONF_AP_BEACON_MISS_TX] = 3,
111 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
112 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
113 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
114 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
115 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300116 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200117 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300118 },
119 .rx = {
120 .rx_msdu_life_time = 512000,
121 .packet_detection_threshold = 0,
122 .ps_poll_timeout = 15,
123 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300124 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200125 .rx_cca_threshold = 0,
126 .irq_blk_threshold = 0xFFFF,
127 .irq_pkt_threshold = 0,
128 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300129 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
130 },
131 .tx = {
132 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200133 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300134 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .short_retry_limit = 10,
136 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200137 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300138 },
139 .ac_conf_count = 4,
140 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_BE,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = 3,
146 .tx_op_limit = 0,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_BK,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = 7,
153 .tx_op_limit = 0,
154 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200155 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300156 .ac = CONF_TX_AC_VI,
157 .cw_min = 15,
158 .cw_max = 63,
159 .aifsn = CONF_TX_AIFS_PIFS,
160 .tx_op_limit = 3008,
161 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200162 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300163 .ac = CONF_TX_AC_VO,
164 .cw_min = 15,
165 .cw_max = 63,
166 .aifsn = CONF_TX_AIFS_PIFS,
167 .tx_op_limit = 1504,
168 },
169 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300170 .max_tx_retries = 100,
171 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200172 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300173 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 [CONF_TX_AC_BE] = {
175 .queue_id = CONF_TX_AC_BE,
176 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .tsid = CONF_TX_AC_BE,
178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200182 [CONF_TX_AC_BK] = {
183 .queue_id = CONF_TX_AC_BK,
184 .channel_type = CONF_CHANNEL_TYPE_EDCF,
185 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_VI] = {
191 .queue_id = CONF_TX_AC_VI,
192 .channel_type = CONF_CHANNEL_TYPE_EDCF,
193 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300194 .ps_scheme = CONF_PS_SCHEME_LEGACY,
195 .ack_policy = CONF_ACK_POLICY_LEGACY,
196 .apsd_conf = {0, 0},
197 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200198 [CONF_TX_AC_VO] = {
199 .queue_id = CONF_TX_AC_VO,
200 .channel_type = CONF_CHANNEL_TYPE_EDCF,
201 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300202 .ps_scheme = CONF_PS_SCHEME_LEGACY,
203 .ack_policy = CONF_ACK_POLICY_LEGACY,
204 .apsd_conf = {0, 0},
205 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300206 },
207 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200208 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300209 .tx_compl_threshold = 4,
210 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
211 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200212 .tmpl_short_retry_limit = 10,
213 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300214 },
215 .conn = {
216 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300217 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300219 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_ie = {
221 [0] = {
222 .ie = WLAN_EID_CHANNEL_SWITCH,
223 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300224 },
225 [1] = {
226 .ie = WLAN_EID_HT_INFORMATION,
227 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200230 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 .bss_lose_timeout = 100,
232 .beacon_rx_timeout = 10000,
233 .broadcast_timeout = 20000,
234 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300235 .ps_poll_threshold = 10,
236 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300237 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e02011-03-14 18:53:10 +0200238 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300239 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300240 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200241 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300242 .keep_alive_interval = 55000,
243 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300244 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200245 .itrim = {
246 .enable = false,
247 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200248 },
249 .pm_config = {
250 .host_clk_settling_time = 5000,
251 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300252 },
253 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 .trigger_pacing = 1,
255 .avg_weight_rssi_beacon = 20,
256 .avg_weight_rssi_data = 10,
257 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100258 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200259 },
260 .scan = {
261 .min_dwell_time_active = 7500,
262 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100263 .min_dwell_time_passive = 100000,
264 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200265 .num_probe_reqs = 2,
266 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300267 .sched_scan = {
268 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300269 .min_dwell_time_active = 30,
270 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300271 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300272 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .num_probe_reqs = 2,
274 .rssi_threshold = -90,
275 .snr_threshold = 0,
276 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200277 .rf = {
278 .tx_per_channel_power_compensation_2 = {
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 },
281 .tx_per_channel_power_compensation_5 = {
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 },
286 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100287 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300288 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .tx_ba_win_size = 64,
290 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300291 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100292 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200293 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200294 .num_stations = 1,
295 .ssid_profiles = 1,
296 .rx_block_num = 70,
297 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300298 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200299 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200300 .min_req_rx_blocks = 22,
301 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200302 },
303 .mem_wl128x = {
304 .num_stations = 1,
305 .ssid_profiles = 1,
306 .rx_block_num = 40,
307 .tx_min_block_num = 40,
308 .dynamic_memory = 1,
309 .min_req_tx_blocks = 45,
310 .min_req_rx_blocks = 22,
311 .tx_min = 27,
312 },
Shahar Leviff868432011-04-11 15:41:46 +0300313 .fm_coex = {
314 .enable = true,
315 .swallow_period = 5,
316 .n_divider_fref_set_1 = 0xff, /* default */
317 .n_divider_fref_set_2 = 12,
318 .m_divider_fref_set_1 = 148,
319 .m_divider_fref_set_2 = 0xffff, /* default */
320 .coex_pll_stabilization_time = 0xffffffff, /* default */
321 .ldo_stabilization_time = 0xffff, /* default */
322 .fm_disturbed_band_margin = 0xff, /* default */
323 .swallow_clk_diff = 0xff, /* default */
324 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300325 .rx_streaming = {
326 .duration = 150,
327 .queues = 0x1,
328 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300329 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300330 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300331 .fwlog = {
332 .mode = WL12XX_FWLOG_ON_DEMAND,
333 .mem_blocks = 2,
334 .severity = 0,
335 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
336 .output = WL12XX_FWLOG_OUTPUT_HOST,
337 .threshold = 0,
338 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300339 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300340 .rate = {
341 .rate_retry_score = 32000,
342 .per_add = 8192,
343 .per_th1 = 2048,
344 .per_th2 = 4096,
345 .max_per = 8100,
346 .inverse_curiosity_factor = 5,
347 .tx_fail_low_th = 4,
348 .tx_fail_high_th = 10,
349 .per_alpha_shift = 4,
350 .per_add_shift = 13,
351 .per_beta1_shift = 10,
352 .per_beta2_shift = 8,
353 .rate_check_up = 2,
354 .rate_check_down = 12,
355 .rate_retry_policy = {
356 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00,
359 },
360 },
Eliad Peller94877752011-08-28 15:11:56 +0300361 .hangover = {
362 .recover_time = 0,
363 .hangover_period = 20,
364 .dynamic_mode = 1,
365 .early_termination_mode = 1,
366 .max_period = 20,
367 .min_period = 1,
368 .increase_delta = 1,
369 .decrease_delta = 2,
370 .quiet_time = 4,
371 .increase_time = 1,
372 .window_size = 16,
373 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300374};
375
Ido Yariv95dac04f2011-06-06 14:57:06 +0300376static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300377static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300379static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200380 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300381 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200382static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200383
384
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200385static void wl1271_device_release(struct device *dev)
386{
387
388}
389
390static struct platform_device wl1271_device = {
391 .name = "wl1271",
392 .id = -1,
393
394 /* device model insists to have a release function */
395 .dev = {
396 .release = wl1271_device_release,
397 },
398};
399
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200400static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300401static LIST_HEAD(wl_list);
402
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300403static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
404{
405 int ret;
406 if (operstate != IF_OPER_UP)
407 return 0;
408
409 if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
410 return 0;
411
Eliad Pellerb67476e2011-08-14 13:17:23 +0300412 ret = wl12xx_cmd_set_peer_state(wl, wl->sta_hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300413 if (ret < 0)
414 return ret;
415
Eliad Peller251c1772011-08-14 13:17:17 +0300416 wl12xx_croc(wl, wl->role_id);
417
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300418 wl1271_info("Association completed.");
419 return 0;
420}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300421static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
422 void *arg)
423{
424 struct net_device *dev = arg;
425 struct wireless_dev *wdev;
426 struct wiphy *wiphy;
427 struct ieee80211_hw *hw;
428 struct wl1271 *wl;
429 struct wl1271 *wl_temp;
430 int ret = 0;
431
432 /* Check that this notification is for us. */
433 if (what != NETDEV_CHANGE)
434 return NOTIFY_DONE;
435
436 wdev = dev->ieee80211_ptr;
437 if (wdev == NULL)
438 return NOTIFY_DONE;
439
440 wiphy = wdev->wiphy;
441 if (wiphy == NULL)
442 return NOTIFY_DONE;
443
444 hw = wiphy_priv(wiphy);
445 if (hw == NULL)
446 return NOTIFY_DONE;
447
448 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200449 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300450 list_for_each_entry(wl, &wl_list, list) {
451 if (wl == wl_temp)
452 break;
453 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200454 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300455 if (wl != wl_temp)
456 return NOTIFY_DONE;
457
458 mutex_lock(&wl->mutex);
459
460 if (wl->state == WL1271_STATE_OFF)
461 goto out;
462
463 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
464 goto out;
465
Ido Yariva6208652011-03-01 15:14:41 +0200466 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300467 if (ret < 0)
468 goto out;
469
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300470 wl1271_check_operstate(wl, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300471
472 wl1271_ps_elp_sleep(wl);
473
474out:
475 mutex_unlock(&wl->mutex);
476
477 return NOTIFY_OK;
478}
479
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100480static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200481 struct regulatory_request *request)
482{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100483 struct ieee80211_supported_band *band;
484 struct ieee80211_channel *ch;
485 int i;
486
487 band = wiphy->bands[IEEE80211_BAND_5GHZ];
488 for (i = 0; i < band->n_channels; i++) {
489 ch = &band->channels[i];
490 if (ch->flags & IEEE80211_CHAN_DISABLED)
491 continue;
492
493 if (ch->flags & IEEE80211_CHAN_RADAR)
494 ch->flags |= IEEE80211_CHAN_NO_IBSS |
495 IEEE80211_CHAN_PASSIVE_SCAN;
496
497 }
498
499 return 0;
500}
501
Eliad Peller77ddaa12011-05-15 11:10:29 +0300502static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
503{
504 int ret = 0;
505
506 /* we should hold wl->mutex */
507 ret = wl1271_acx_ps_rx_streaming(wl, enable);
508 if (ret < 0)
509 goto out;
510
511 if (enable)
512 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
513 else
514 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
515out:
516 return ret;
517}
518
519/*
520 * this function is being called when the rx_streaming interval
521 * has beed changed or rx_streaming should be disabled
522 */
523int wl1271_recalc_rx_streaming(struct wl1271 *wl)
524{
525 int ret = 0;
526 int period = wl->conf.rx_streaming.interval;
527
528 /* don't reconfigure if rx_streaming is disabled */
529 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
530 goto out;
531
532 /* reconfigure/disable according to new streaming_period */
533 if (period &&
534 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
535 (wl->conf.rx_streaming.always ||
536 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
537 ret = wl1271_set_rx_streaming(wl, true);
538 else {
539 ret = wl1271_set_rx_streaming(wl, false);
540 /* don't cancel_work_sync since we might deadlock */
541 del_timer_sync(&wl->rx_streaming_timer);
542 }
543out:
544 return ret;
545}
546
547static void wl1271_rx_streaming_enable_work(struct work_struct *work)
548{
549 int ret;
550 struct wl1271 *wl =
551 container_of(work, struct wl1271, rx_streaming_enable_work);
552
553 mutex_lock(&wl->mutex);
554
555 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
556 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
557 (!wl->conf.rx_streaming.always &&
558 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
559 goto out;
560
561 if (!wl->conf.rx_streaming.interval)
562 goto out;
563
564 ret = wl1271_ps_elp_wakeup(wl);
565 if (ret < 0)
566 goto out;
567
568 ret = wl1271_set_rx_streaming(wl, true);
569 if (ret < 0)
570 goto out_sleep;
571
572 /* stop it after some time of inactivity */
573 mod_timer(&wl->rx_streaming_timer,
574 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
575
576out_sleep:
577 wl1271_ps_elp_sleep(wl);
578out:
579 mutex_unlock(&wl->mutex);
580}
581
582static void wl1271_rx_streaming_disable_work(struct work_struct *work)
583{
584 int ret;
585 struct wl1271 *wl =
586 container_of(work, struct wl1271, rx_streaming_disable_work);
587
588 mutex_lock(&wl->mutex);
589
590 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
591 goto out;
592
593 ret = wl1271_ps_elp_wakeup(wl);
594 if (ret < 0)
595 goto out;
596
597 ret = wl1271_set_rx_streaming(wl, false);
598 if (ret)
599 goto out_sleep;
600
601out_sleep:
602 wl1271_ps_elp_sleep(wl);
603out:
604 mutex_unlock(&wl->mutex);
605}
606
607static void wl1271_rx_streaming_timer(unsigned long data)
608{
609 struct wl1271 *wl = (struct wl1271 *)data;
610 ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
611}
612
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300613static void wl1271_conf_init(struct wl1271 *wl)
614{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300615
616 /*
617 * This function applies the default configuration to the driver. This
618 * function is invoked upon driver load (spi probe.)
619 *
620 * The configuration is stored in a run-time structure in order to
621 * facilitate for run-time adjustment of any of the parameters. Making
622 * changes to the configuration structure will apply the new values on
623 * the next interface up (wl1271_op_start.)
624 */
625
626 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300627 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300628
Ido Yariv95dac04f2011-06-06 14:57:06 +0300629 /* Adjust settings according to optional module parameters */
630 if (fwlog_param) {
631 if (!strcmp(fwlog_param, "continuous")) {
632 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
633 } else if (!strcmp(fwlog_param, "ondemand")) {
634 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
635 } else if (!strcmp(fwlog_param, "dbgpins")) {
636 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
637 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
638 } else if (!strcmp(fwlog_param, "disable")) {
639 wl->conf.fwlog.mem_blocks = 0;
640 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
641 } else {
642 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
643 }
644 }
645}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300646
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300647static int wl1271_plt_init(struct wl1271 *wl)
648{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200649 struct conf_tx_ac_category *conf_ac;
650 struct conf_tx_tid *conf_tid;
651 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300652
Shahar Levi49d750ca2011-03-06 16:32:09 +0200653 if (wl->chip.id == CHIP_ID_1283_PG20)
654 ret = wl128x_cmd_general_parms(wl);
655 else
656 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200657 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200658 return ret;
659
Shahar Levi49d750ca2011-03-06 16:32:09 +0200660 if (wl->chip.id == CHIP_ID_1283_PG20)
661 ret = wl128x_cmd_radio_parms(wl);
662 else
663 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200664 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200665 return ret;
666
Shahar Levi49d750ca2011-03-06 16:32:09 +0200667 if (wl->chip.id != CHIP_ID_1283_PG20) {
668 ret = wl1271_cmd_ext_radio_parms(wl);
669 if (ret < 0)
670 return ret;
671 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200672 if (ret < 0)
673 return ret;
674
Shahar Levi48a61472011-03-06 16:32:08 +0200675 /* Chip-specific initializations */
676 ret = wl1271_chip_specific_init(wl);
677 if (ret < 0)
678 return ret;
679
Eliad Peller92c77c72011-10-05 11:55:40 +0200680 ret = wl1271_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200681 if (ret < 0)
682 return ret;
683
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300684 ret = wl1271_acx_init_mem_config(wl);
685 if (ret < 0)
686 return ret;
687
Luciano Coelho12419cc2010-02-18 13:25:44 +0200688 /* PHY layer config */
689 ret = wl1271_init_phy_config(wl);
690 if (ret < 0)
691 goto out_free_memmap;
692
693 ret = wl1271_acx_dco_itrim_params(wl);
694 if (ret < 0)
695 goto out_free_memmap;
696
697 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200698 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200699 if (ret < 0)
700 goto out_free_memmap;
701
702 /* Bluetooth WLAN coexistence */
703 ret = wl1271_init_pta(wl);
704 if (ret < 0)
705 goto out_free_memmap;
706
Shahar Leviff868432011-04-11 15:41:46 +0300707 /* FM WLAN coexistence */
708 ret = wl1271_acx_fm_coex(wl);
709 if (ret < 0)
710 goto out_free_memmap;
711
Luciano Coelho12419cc2010-02-18 13:25:44 +0200712 /* Energy detection */
713 ret = wl1271_init_energy_detection(wl);
714 if (ret < 0)
715 goto out_free_memmap;
716
Eliad Peller7f0979882011-08-14 13:17:06 +0300717 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600718 if (ret < 0)
719 goto out_free_memmap;
720
Luciano Coelho12419cc2010-02-18 13:25:44 +0200721 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100722 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200723 if (ret < 0)
724 goto out_free_memmap;
725
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200726 /* Default TID/AC configuration */
727 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200728 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200729 conf_ac = &wl->conf.tx.ac_conf[i];
730 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
731 conf_ac->cw_max, conf_ac->aifsn,
732 conf_ac->tx_op_limit);
733 if (ret < 0)
734 goto out_free_memmap;
735
Luciano Coelho12419cc2010-02-18 13:25:44 +0200736 conf_tid = &wl->conf.tx.tid_conf[i];
737 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
738 conf_tid->channel_type,
739 conf_tid->tsid,
740 conf_tid->ps_scheme,
741 conf_tid->ack_policy,
742 conf_tid->apsd_conf[0],
743 conf_tid->apsd_conf[1]);
744 if (ret < 0)
745 goto out_free_memmap;
746 }
747
Luciano Coelho12419cc2010-02-18 13:25:44 +0200748 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200749 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300750 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200751 goto out_free_memmap;
752
753 /* Configure for CAM power saving (ie. always active) */
754 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
755 if (ret < 0)
756 goto out_free_memmap;
757
758 /* configure PM */
759 ret = wl1271_acx_pm_config(wl);
760 if (ret < 0)
761 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300762
763 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200764
765 out_free_memmap:
766 kfree(wl->target_mem_map);
767 wl->target_mem_map = NULL;
768
769 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300770}
771
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300772static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200773{
Arik Nemtsovda032092011-08-25 12:43:15 +0300774 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200775
776 /* only regulate station links */
777 if (hlid < WL1271_AP_STA_HLID_START)
778 return;
779
780 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300781 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200782
783 /*
784 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300785 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200786 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300787 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200788 wl1271_ps_link_end(wl, hlid);
789
Arik Nemtsovda032092011-08-25 12:43:15 +0300790 /*
791 * Start high-level PS if the STA is asleep with enough blocks in FW.
792 * Make an exception if this is the only connected station. In this
793 * case FW-memory congestion is not a problem.
794 */
795 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200796 wl1271_ps_link_start(wl, hlid, true);
797}
798
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300799bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
800{
Arik Nemtsov04216da2011-08-14 13:17:38 +0300801 int id;
802
803 /* global/broadcast "stations" are always active */
804 if (hlid < WL1271_AP_STA_HLID_START)
805 return true;
806
807 id = hlid - WL1271_AP_STA_HLID_START;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300808 return test_bit(id, wl->ap_hlid_map);
809}
810
811static void wl12xx_irq_update_links_status(struct wl1271 *wl,
812 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200813{
814 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300815 u8 hlid, cnt;
816
817 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200818
819 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
820 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
821 wl1271_debug(DEBUG_PSM,
822 "link ps prev 0x%x cur 0x%x changed 0x%x",
823 wl->ap_fw_ps_map, cur_fw_ps_map,
824 wl->ap_fw_ps_map ^ cur_fw_ps_map);
825
826 wl->ap_fw_ps_map = cur_fw_ps_map;
827 }
828
829 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300830 if (!wl1271_is_active_sta(wl, hlid))
831 continue;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200832
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300833 cnt = status->tx_lnk_free_pkts[hlid] -
834 wl->links[hlid].prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200835
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300836 wl->links[hlid].prev_freed_pkts =
837 status->tx_lnk_free_pkts[hlid];
838 wl->links[hlid].allocated_pkts -= cnt;
839
840 wl12xx_irq_ps_regulate_link(wl, hlid,
841 wl->links[hlid].allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200842 }
843}
844
Eliad Peller4d56ad92011-08-14 13:17:05 +0300845static void wl12xx_fw_status(struct wl1271 *wl,
846 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300847{
Eliad Peller536129c2011-10-05 11:55:45 +0200848 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
849 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200850 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200851 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300852 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300853 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300854
Eliad Peller4d56ad92011-08-14 13:17:05 +0300855 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200856
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300857 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
858 "drv_rx_counter = %d, tx_results_counter = %d)",
859 status->intr,
860 status->fw_rx_counter,
861 status->drv_rx_counter,
862 status->tx_results_counter);
863
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300864 for (i = 0; i < NUM_TX_QUEUES; i++) {
865 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300866 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300867 (status->tx_released_pkts[i] -
868 wl->tx_pkts_freed[i]) & 0xff;
869
870 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
871 }
872
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300873 /* prevent wrap-around in total blocks counter */
874 if (likely(wl->tx_blocks_freed <=
875 le32_to_cpu(status->total_released_blks)))
876 freed_blocks = le32_to_cpu(status->total_released_blks) -
877 wl->tx_blocks_freed;
878 else
879 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
880 le32_to_cpu(status->total_released_blks);
881
Eliad Peller4d56ad92011-08-14 13:17:05 +0300882 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200883
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300884 wl->tx_allocated_blocks -= freed_blocks;
885
Eliad Peller4d56ad92011-08-14 13:17:05 +0300886 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200887
Eliad Peller4d56ad92011-08-14 13:17:05 +0300888 /*
889 * The FW might change the total number of TX memblocks before
890 * we get a notification about blocks being released. Thus, the
891 * available blocks calculation might yield a temporary result
892 * which is lower than the actual available blocks. Keeping in
893 * mind that only blocks that were allocated can be moved from
894 * TX to RX, tx_blocks_available should never decrease here.
895 */
896 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
897 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300898
Ido Yariva5225502010-10-12 14:49:10 +0200899 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200900 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200901 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902
Eliad Peller4d56ad92011-08-14 13:17:05 +0300903 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller536129c2011-10-05 11:55:45 +0200904 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300905 wl12xx_irq_update_links_status(wl, status);
Eliad Peller4d56ad92011-08-14 13:17:05 +0300906
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300907 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200908 getnstimeofday(&ts);
909 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
910 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911}
912
Ido Yariva6208652011-03-01 15:14:41 +0200913static void wl1271_flush_deferred_work(struct wl1271 *wl)
914{
915 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200916
Ido Yariva6208652011-03-01 15:14:41 +0200917 /* Pass all received frames to the network stack */
918 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
919 ieee80211_rx_ni(wl->hw, skb);
920
921 /* Return sent skbs to the network stack */
922 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300923 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200924}
925
926static void wl1271_netstack_work(struct work_struct *work)
927{
928 struct wl1271 *wl =
929 container_of(work, struct wl1271, netstack_work);
930
931 do {
932 wl1271_flush_deferred_work(wl);
933 } while (skb_queue_len(&wl->deferred_rx_queue));
934}
935
936#define WL1271_IRQ_MAX_LOOPS 256
937
938irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300939{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300940 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300941 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200942 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200943 struct wl1271 *wl = (struct wl1271 *)cookie;
944 bool done = false;
945 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200946 unsigned long flags;
947
948 /* TX might be handled here, avoid redundant work */
949 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
950 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300951
Ido Yariv341b7cd2011-03-31 10:07:01 +0200952 /*
953 * In case edge triggered interrupt must be used, we cannot iterate
954 * more than once without introducing race conditions with the hardirq.
955 */
956 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
957 loopcount = 1;
958
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300959 mutex_lock(&wl->mutex);
960
961 wl1271_debug(DEBUG_IRQ, "IRQ work");
962
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200963 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300964 goto out;
965
Ido Yariva6208652011-03-01 15:14:41 +0200966 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300967 if (ret < 0)
968 goto out;
969
Ido Yariva6208652011-03-01 15:14:41 +0200970 while (!done && loopcount--) {
971 /*
972 * In order to avoid a race with the hardirq, clear the flag
973 * before acknowledging the chip. Since the mutex is held,
974 * wl1271_ps_elp_wakeup cannot be called concurrently.
975 */
976 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
977 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200978
Eliad Peller4d56ad92011-08-14 13:17:05 +0300979 wl12xx_fw_status(wl, wl->fw_status);
980 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200981 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200982 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200983 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200984 continue;
985 }
986
Eliad Pellerccc83b02010-10-27 14:09:57 +0200987 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
988 wl1271_error("watchdog interrupt received! "
989 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300990 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200991
992 /* restarting the chip. ignore any other interrupt. */
993 goto out;
994 }
995
Ido Yariva6208652011-03-01 15:14:41 +0200996 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200997 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
998
Eliad Peller4d56ad92011-08-14 13:17:05 +0300999 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001000
Ido Yariva5225502010-10-12 14:49:10 +02001001 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +02001002 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001003 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001004 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +02001005 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001006 /*
1007 * In order to avoid starvation of the TX path,
1008 * call the work function directly.
1009 */
Eliad Peller536129c2011-10-05 11:55:45 +02001010 wl1271_tx_work_locked(wl, wl->vif);
Ido Yarivb07d4032011-03-01 15:14:43 +02001011 } else {
1012 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001013 }
1014
Ido Yariv8aad2462011-03-01 15:14:38 +02001015 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001016 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +02001017 (wl->tx_results_count & 0xff))
1018 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001019
1020 /* Make sure the deferred queues don't get too long */
1021 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1022 skb_queue_len(&wl->deferred_rx_queue);
1023 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1024 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001025 }
1026
1027 if (intr & WL1271_ACX_INTR_EVENT_A) {
1028 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1029 wl1271_event_handle(wl, 0);
1030 }
1031
1032 if (intr & WL1271_ACX_INTR_EVENT_B) {
1033 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1034 wl1271_event_handle(wl, 1);
1035 }
1036
1037 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1038 wl1271_debug(DEBUG_IRQ,
1039 "WL1271_ACX_INTR_INIT_COMPLETE");
1040
1041 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1042 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043 }
1044
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045 wl1271_ps_elp_sleep(wl);
1046
1047out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001048 spin_lock_irqsave(&wl->wl_lock, flags);
1049 /* In case TX was not handled here, queue TX work */
1050 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1051 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001052 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001053 ieee80211_queue_work(wl->hw, &wl->tx_work);
1054 spin_unlock_irqrestore(&wl->wl_lock, flags);
1055
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001057
1058 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001059}
Ido Yariva6208652011-03-01 15:14:41 +02001060EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001061
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062static int wl1271_fetch_firmware(struct wl1271 *wl)
1063{
1064 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001065 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066 int ret;
1067
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001068 if (wl->chip.id == CHIP_ID_1283_PG20)
1069 fw_name = WL128X_FW_NAME;
1070 else
1071 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001072
1073 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1074
1075 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001076
1077 if (ret < 0) {
1078 wl1271_error("could not get firmware: %d", ret);
1079 return ret;
1080 }
1081
1082 if (fw->size % 4) {
1083 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1084 fw->size);
1085 ret = -EILSEQ;
1086 goto out;
1087 }
1088
Arik Nemtsov166d5042010-10-16 21:44:57 +02001089 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001090 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001091 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001092
1093 if (!wl->fw) {
1094 wl1271_error("could not allocate memory for the firmware");
1095 ret = -ENOMEM;
1096 goto out;
1097 }
1098
1099 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001100 ret = 0;
1101
1102out:
1103 release_firmware(fw);
1104
1105 return ret;
1106}
1107
1108static int wl1271_fetch_nvs(struct wl1271 *wl)
1109{
1110 const struct firmware *fw;
1111 int ret;
1112
Shahar Levi5aa42342011-03-06 16:32:07 +02001113 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001114
1115 if (ret < 0) {
1116 wl1271_error("could not get nvs file: %d", ret);
1117 return ret;
1118 }
1119
Shahar Levibc765bf2011-03-06 16:32:10 +02001120 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001121
1122 if (!wl->nvs) {
1123 wl1271_error("could not allocate memory for the nvs file");
1124 ret = -ENOMEM;
1125 goto out;
1126 }
1127
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001128 wl->nvs_len = fw->size;
1129
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001130out:
1131 release_firmware(fw);
1132
1133 return ret;
1134}
1135
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001136void wl12xx_queue_recovery_work(struct wl1271 *wl)
1137{
1138 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1139 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1140}
1141
Ido Yariv95dac04f2011-06-06 14:57:06 +03001142size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1143{
1144 size_t len = 0;
1145
1146 /* The FW log is a length-value list, find where the log end */
1147 while (len < maxlen) {
1148 if (memblock[len] == 0)
1149 break;
1150 if (len + memblock[len] + 1 > maxlen)
1151 break;
1152 len += memblock[len] + 1;
1153 }
1154
1155 /* Make sure we have enough room */
1156 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1157
1158 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1159 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1160 wl->fwlog_size += len;
1161
1162 return len;
1163}
1164
1165static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1166{
1167 u32 addr;
1168 u32 first_addr;
1169 u8 *block;
1170
1171 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1172 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1173 (wl->conf.fwlog.mem_blocks == 0))
1174 return;
1175
1176 wl1271_info("Reading FW panic log");
1177
1178 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1179 if (!block)
1180 return;
1181
1182 /*
1183 * Make sure the chip is awake and the logger isn't active.
1184 * This might fail if the firmware hanged.
1185 */
1186 if (!wl1271_ps_elp_wakeup(wl))
1187 wl12xx_cmd_stop_fwlog(wl);
1188
1189 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001190 wl12xx_fw_status(wl, wl->fw_status);
1191 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001192 if (!first_addr)
1193 goto out;
1194
1195 /* Traverse the memory blocks linked list */
1196 addr = first_addr;
1197 do {
1198 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1199 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1200 false);
1201
1202 /*
1203 * Memory blocks are linked to one another. The first 4 bytes
1204 * of each memory block hold the hardware address of the next
1205 * one. The last memory block points to the first one.
1206 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001207 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001208 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1209 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1210 break;
1211 } while (addr && (addr != first_addr));
1212
1213 wake_up_interruptible(&wl->fwlog_waitq);
1214
1215out:
1216 kfree(block);
1217}
1218
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001219static void wl1271_recovery_work(struct work_struct *work)
1220{
1221 struct wl1271 *wl =
1222 container_of(work, struct wl1271, recovery_work);
1223
1224 mutex_lock(&wl->mutex);
1225
1226 if (wl->state != WL1271_STATE_ON)
1227 goto out;
1228
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001229 /* Avoid a recursive recovery */
1230 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1231
Ido Yariv95dac04f2011-06-06 14:57:06 +03001232 wl12xx_read_fwlog_panic(wl);
1233
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001234 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1235 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001236
Eliad Peller2a5bff02011-08-25 18:10:59 +03001237 BUG_ON(bug_on_recovery);
1238
Oz Krakowskib992c682011-06-26 10:36:02 +03001239 /*
1240 * Advance security sequence number to overcome potential progress
1241 * in the firmware during recovery. This doens't hurt if the network is
1242 * not encrypted.
1243 */
1244 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1245 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1246 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1247
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001248 /* Prevent spurious TX during FW restart */
1249 ieee80211_stop_queues(wl->hw);
1250
Luciano Coelho33c2c062011-05-10 14:46:02 +03001251 if (wl->sched_scanning) {
1252 ieee80211_sched_scan_stopped(wl->hw);
1253 wl->sched_scanning = false;
1254 }
1255
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001256 /* reboot the chipset */
Eliad Peller536129c2011-10-05 11:55:45 +02001257 __wl1271_op_remove_interface(wl, wl->vif, false);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001258
1259 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1260
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001261 ieee80211_restart_hw(wl->hw);
1262
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001263 /*
1264 * Its safe to enable TX now - the queues are stopped after a request
1265 * to restart the HW.
1266 */
1267 ieee80211_wake_queues(wl->hw);
1268
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001269out:
1270 mutex_unlock(&wl->mutex);
1271}
1272
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273static void wl1271_fw_wakeup(struct wl1271 *wl)
1274{
1275 u32 elp_reg;
1276
1277 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001278 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001279}
1280
1281static int wl1271_setup(struct wl1271 *wl)
1282{
1283 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1284 if (!wl->fw_status)
1285 return -ENOMEM;
1286
1287 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1288 if (!wl->tx_res_if) {
1289 kfree(wl->fw_status);
1290 return -ENOMEM;
1291 }
1292
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001293 return 0;
1294}
1295
1296static int wl1271_chip_wakeup(struct wl1271 *wl)
1297{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001298 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001299 int ret = 0;
1300
Juuso Oikarinen01ac17ec2009-12-11 15:41:02 +02001301 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001302 ret = wl1271_power_on(wl);
1303 if (ret < 0)
1304 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001305 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001306 wl1271_io_reset(wl);
1307 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001308
1309 /* We don't need a real memory partition here, because we only want
1310 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001311 memset(&partition, 0, sizeof(partition));
1312 partition.reg.start = REGISTERS_BASE;
1313 partition.reg.size = REGISTERS_DOWN_SIZE;
1314 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315
1316 /* ELP module wake up */
1317 wl1271_fw_wakeup(wl);
1318
1319 /* whal_FwCtrl_BootSm() */
1320
1321 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001322 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001323
1324 /* 1. check if chip id is valid */
1325
1326 switch (wl->chip.id) {
1327 case CHIP_ID_1271_PG10:
1328 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1329 wl->chip.id);
1330
1331 ret = wl1271_setup(wl);
1332 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001333 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001334 break;
1335 case CHIP_ID_1271_PG20:
1336 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1337 wl->chip.id);
1338
1339 ret = wl1271_setup(wl);
1340 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001341 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001342 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001343 case CHIP_ID_1283_PG20:
1344 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1345 wl->chip.id);
1346
1347 ret = wl1271_setup(wl);
1348 if (ret < 0)
1349 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001350
Ido Yariv0da13da2011-03-31 10:06:58 +02001351 if (wl1271_set_block_size(wl))
1352 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001353 break;
1354 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001355 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001356 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001358 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359 }
1360
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001361 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362 ret = wl1271_fetch_firmware(wl);
1363 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001364 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001365 }
1366
1367 /* No NVS from netlink, try to get it from the filesystem */
1368 if (wl->nvs == NULL) {
1369 ret = wl1271_fetch_nvs(wl);
1370 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001371 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001372 }
1373
1374out:
1375 return ret;
1376}
1377
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001378int wl1271_plt_start(struct wl1271 *wl)
1379{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001380 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001381 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382 int ret;
1383
1384 mutex_lock(&wl->mutex);
1385
1386 wl1271_notice("power up");
1387
1388 if (wl->state != WL1271_STATE_OFF) {
1389 wl1271_error("cannot go into PLT state because not "
1390 "in off state: %d", wl->state);
1391 ret = -EBUSY;
1392 goto out;
1393 }
1394
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001395 while (retries) {
1396 retries--;
1397 ret = wl1271_chip_wakeup(wl);
1398 if (ret < 0)
1399 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001400
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001401 ret = wl1271_boot(wl);
1402 if (ret < 0)
1403 goto power_off;
1404
1405 ret = wl1271_plt_init(wl);
1406 if (ret < 0)
1407 goto irq_disable;
1408
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001409 wl->state = WL1271_STATE_PLT;
1410 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001411 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001412
Gery Kahn6f07b722011-07-18 14:21:49 +03001413 /* update hw/fw version info in wiphy struct */
1414 wiphy->hw_version = wl->chip.id;
1415 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1416 sizeof(wiphy->fw_version));
1417
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001418 goto out;
1419
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001420irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001421 mutex_unlock(&wl->mutex);
1422 /* Unlocking the mutex in the middle of handling is
1423 inherently unsafe. In this case we deem it safe to do,
1424 because we need to let any possibly pending IRQ out of
1425 the system (and while we are WL1271_STATE_OFF the IRQ
1426 work function will not do anything.) Also, any other
1427 possible concurrent operations will fail due to the
1428 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001429 wl1271_disable_interrupts(wl);
1430 wl1271_flush_deferred_work(wl);
1431 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001432 mutex_lock(&wl->mutex);
1433power_off:
1434 wl1271_power_off(wl);
1435 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001436
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001437 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1438 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001439out:
1440 mutex_unlock(&wl->mutex);
1441
1442 return ret;
1443}
1444
Luciano Coelho4623ec72011-03-21 19:26:41 +02001445static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001446{
1447 int ret = 0;
1448
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001449 wl1271_notice("power down");
1450
1451 if (wl->state != WL1271_STATE_PLT) {
1452 wl1271_error("cannot power down because not in PLT "
1453 "state: %d", wl->state);
1454 ret = -EBUSY;
1455 goto out;
1456 }
1457
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001458 wl1271_power_off(wl);
1459
1460 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001461 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001462
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001463 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001464 wl1271_disable_interrupts(wl);
1465 wl1271_flush_deferred_work(wl);
1466 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001467 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001468 mutex_lock(&wl->mutex);
1469out:
1470 return ret;
1471}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001472
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001473int wl1271_plt_stop(struct wl1271 *wl)
1474{
1475 int ret;
1476
1477 mutex_lock(&wl->mutex);
1478 ret = __wl1271_plt_stop(wl);
1479 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001480 return ret;
1481}
1482
Johannes Berg7bb45682011-02-24 14:42:06 +01001483static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001484{
1485 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02001486 struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb);
1487 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(control->control.vif);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001488 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001489 int q, mapping;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001490 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001491
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001492 mapping = skb_get_queue_mapping(skb);
1493 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001494
Eliad Peller536129c2011-10-05 11:55:45 +02001495 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03001496 hlid = wl12xx_tx_get_hlid_ap(wl, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001497
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001498 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001499
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001500 /* queue the packet */
Eliad Peller536129c2011-10-05 11:55:45 +02001501 if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov04216da2011-08-14 13:17:38 +03001502 if (!wl1271_is_active_sta(wl, hlid)) {
1503 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d",
1504 hlid, q);
1505 dev_kfree_skb(skb);
1506 goto out;
1507 }
1508
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001509 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1510 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1511 } else {
1512 skb_queue_tail(&wl->tx_queue[q], skb);
1513 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001514
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001515 wl->tx_queue_count[q]++;
1516
1517 /*
1518 * The workqueue is slow to process the tx_queue and we need stop
1519 * the queue here, otherwise the queue will get too long.
1520 */
1521 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1522 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1523 ieee80211_stop_queue(wl->hw, mapping);
1524 set_bit(q, &wl->stopped_queues_map);
1525 }
1526
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001527 /*
1528 * The chip specific setup must run before the first TX packet -
1529 * before that, the tx_work will not be initialized!
1530 */
1531
Ido Yarivb07d4032011-03-01 15:14:43 +02001532 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1533 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001534 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001535
Arik Nemtsov04216da2011-08-14 13:17:38 +03001536out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001537 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001538}
1539
Shahar Leviae47c452011-03-06 16:32:14 +02001540int wl1271_tx_dummy_packet(struct wl1271 *wl)
1541{
Ido Yariv990f5de2011-03-31 10:06:59 +02001542 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001543 int q;
1544
1545 /* no need to queue a new dummy packet if one is already pending */
1546 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1547 return 0;
1548
1549 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001550
Ido Yariv990f5de2011-03-31 10:06:59 +02001551 spin_lock_irqsave(&wl->wl_lock, flags);
1552 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001553 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001554 spin_unlock_irqrestore(&wl->wl_lock, flags);
1555
1556 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1557 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Peller536129c2011-10-05 11:55:45 +02001558 wl1271_tx_work_locked(wl, wl->vif);
Ido Yariv990f5de2011-03-31 10:06:59 +02001559
1560 /*
1561 * If the FW TX is busy, TX work will be scheduled by the threaded
1562 * interrupt handler function
1563 */
1564 return 0;
1565}
1566
1567/*
1568 * The size of the dummy packet should be at least 1400 bytes. However, in
1569 * order to minimize the number of bus transactions, aligning it to 512 bytes
1570 * boundaries could be beneficial, performance wise
1571 */
1572#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1573
Luciano Coelhocf27d862011-04-01 21:08:23 +03001574static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001575{
1576 struct sk_buff *skb;
1577 struct ieee80211_hdr_3addr *hdr;
1578 unsigned int dummy_packet_size;
1579
1580 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1581 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1582
1583 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001584 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001585 wl1271_warning("Failed to allocate a dummy packet skb");
1586 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001587 }
1588
1589 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1590
1591 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1592 memset(hdr, 0, sizeof(*hdr));
1593 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001594 IEEE80211_STYPE_NULLFUNC |
1595 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001596
Ido Yariv990f5de2011-03-31 10:06:59 +02001597 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001598
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001599 /* Dummy packets require the TID to be management */
1600 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001601
1602 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001603 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001604 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001605
Ido Yariv990f5de2011-03-31 10:06:59 +02001606 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001607}
1608
Ido Yariv990f5de2011-03-31 10:06:59 +02001609
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001610static struct notifier_block wl1271_dev_notifier = {
1611 .notifier_call = wl1271_dev_notify,
1612};
1613
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001614#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001615static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1616 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001617{
Eliad Pellere85d1622011-06-27 13:06:43 +03001618 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001619
Eliad Peller94390642011-05-13 11:57:13 +03001620 mutex_lock(&wl->mutex);
1621
Eliad Pellere85d1622011-06-27 13:06:43 +03001622 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1623 goto out_unlock;
1624
Eliad Peller94390642011-05-13 11:57:13 +03001625 ret = wl1271_ps_elp_wakeup(wl);
1626 if (ret < 0)
1627 goto out_unlock;
1628
1629 /* enter psm if needed*/
1630 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1631 DECLARE_COMPLETION_ONSTACK(compl);
1632
1633 wl->ps_compl = &compl;
1634 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001635 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001636 if (ret < 0)
1637 goto out_sleep;
1638
1639 /* we must unlock here so we will be able to get events */
1640 wl1271_ps_elp_sleep(wl);
1641 mutex_unlock(&wl->mutex);
1642
1643 ret = wait_for_completion_timeout(
1644 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1645 if (ret <= 0) {
1646 wl1271_warning("couldn't enter ps mode!");
1647 ret = -EBUSY;
1648 goto out;
1649 }
1650
1651 /* take mutex again, and wakeup */
1652 mutex_lock(&wl->mutex);
1653
1654 ret = wl1271_ps_elp_wakeup(wl);
1655 if (ret < 0)
1656 goto out_unlock;
1657 }
1658out_sleep:
1659 wl1271_ps_elp_sleep(wl);
1660out_unlock:
1661 mutex_unlock(&wl->mutex);
1662out:
1663 return ret;
1664
1665}
1666
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001667static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001668{
Eliad Pellere85d1622011-06-27 13:06:43 +03001669 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001670
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001671 mutex_lock(&wl->mutex);
1672
Eliad Pellere85d1622011-06-27 13:06:43 +03001673 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1674 goto out_unlock;
1675
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001676 ret = wl1271_ps_elp_wakeup(wl);
1677 if (ret < 0)
1678 goto out_unlock;
1679
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001680 ret = wl1271_acx_beacon_filter_opt(wl, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001681
1682 wl1271_ps_elp_sleep(wl);
1683out_unlock:
1684 mutex_unlock(&wl->mutex);
1685 return ret;
1686
1687}
1688
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001689static int wl1271_configure_suspend(struct wl1271 *wl,
1690 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001691{
Eliad Peller536129c2011-10-05 11:55:45 +02001692 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001693 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001694 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001695 return wl1271_configure_suspend_ap(wl);
1696 return 0;
1697}
1698
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001699static void wl1271_configure_resume(struct wl1271 *wl,
1700 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001701{
1702 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001703 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1704 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001705
1706 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001707 return;
1708
1709 mutex_lock(&wl->mutex);
1710 ret = wl1271_ps_elp_wakeup(wl);
1711 if (ret < 0)
1712 goto out;
1713
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001714 if (is_sta) {
1715 /* exit psm if it wasn't configured */
1716 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1717 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001718 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001719 } else if (is_ap) {
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001720 wl1271_acx_beacon_filter_opt(wl, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001721 }
Eliad Peller94390642011-05-13 11:57:13 +03001722
1723 wl1271_ps_elp_sleep(wl);
1724out:
1725 mutex_unlock(&wl->mutex);
1726}
1727
Eliad Peller402e48612011-05-13 11:57:09 +03001728static int wl1271_op_suspend(struct ieee80211_hw *hw,
1729 struct cfg80211_wowlan *wow)
1730{
1731 struct wl1271 *wl = hw->priv;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001732 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
1733 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001734 int ret;
1735
Eliad Peller402e48612011-05-13 11:57:09 +03001736 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001737 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001738
Eliad Peller4a859df2011-06-06 12:21:52 +03001739 wl->wow_enabled = true;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001740 ret = wl1271_configure_suspend(wl, wlvif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001741 if (ret < 0) {
1742 wl1271_warning("couldn't prepare device to suspend");
1743 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001744 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001745 /* flush any remaining work */
1746 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001747
1748 /*
1749 * disable and re-enable interrupts in order to flush
1750 * the threaded_irq
1751 */
1752 wl1271_disable_interrupts(wl);
1753
1754 /*
1755 * set suspended flag to avoid triggering a new threaded_irq
1756 * work. no need for spinlock as interrupts are disabled.
1757 */
1758 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1759
1760 wl1271_enable_interrupts(wl);
1761 flush_work(&wl->tx_work);
1762 flush_delayed_work(&wl->pspoll_work);
1763 flush_delayed_work(&wl->elp_work);
1764
Eliad Peller402e48612011-05-13 11:57:09 +03001765 return 0;
1766}
1767
1768static int wl1271_op_resume(struct ieee80211_hw *hw)
1769{
1770 struct wl1271 *wl = hw->priv;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001771 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
1772 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001773 unsigned long flags;
1774 bool run_irq_work = false;
1775
Eliad Peller402e48612011-05-13 11:57:09 +03001776 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1777 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001778 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001779
1780 /*
1781 * re-enable irq_work enqueuing, and call irq_work directly if
1782 * there is a pending work.
1783 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001784 spin_lock_irqsave(&wl->wl_lock, flags);
1785 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1786 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1787 run_irq_work = true;
1788 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001789
Eliad Peller4a859df2011-06-06 12:21:52 +03001790 if (run_irq_work) {
1791 wl1271_debug(DEBUG_MAC80211,
1792 "run postponed irq_work directly");
1793 wl1271_irq(0, wl);
1794 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001795 }
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001796 wl1271_configure_resume(wl, wlvif);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001797 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001798
Eliad Peller402e48612011-05-13 11:57:09 +03001799 return 0;
1800}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001801#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001802
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001803static int wl1271_op_start(struct ieee80211_hw *hw)
1804{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001805 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1806
1807 /*
1808 * We have to delay the booting of the hardware because
1809 * we need to know the local MAC address before downloading and
1810 * initializing the firmware. The MAC address cannot be changed
1811 * after boot, and without the proper MAC address, the firmware
1812 * will not function properly.
1813 *
1814 * The MAC address is first known when the corresponding interface
1815 * is added. That is where we will initialize the hardware.
1816 */
1817
1818 return 0;
1819}
1820
1821static void wl1271_op_stop(struct ieee80211_hw *hw)
1822{
1823 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1824}
1825
Eliad Peller536129c2011-10-05 11:55:45 +02001826static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001827{
Eliad Peller536129c2011-10-05 11:55:45 +02001828 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001829 case BSS_TYPE_AP_BSS:
Eliad Peller045c7452011-08-28 15:23:01 +03001830 if (wl->p2p)
1831 return WL1271_ROLE_P2P_GO;
1832 else
1833 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001834
1835 case BSS_TYPE_STA_BSS:
Eliad Peller045c7452011-08-28 15:23:01 +03001836 if (wl->p2p)
1837 return WL1271_ROLE_P2P_CL;
1838 else
1839 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001840
Eliad Peller227e81e2011-08-14 13:17:26 +03001841 case BSS_TYPE_IBSS:
1842 return WL1271_ROLE_IBSS;
1843
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001844 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001845 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001846 }
1847 return WL12XX_INVALID_ROLE_TYPE;
1848}
1849
Eliad Peller87fbcb02011-10-05 11:55:41 +02001850static void wl12xx_init_vif_data(struct wl12xx_vif *wlvif)
1851{
Eliad Peller536129c2011-10-05 11:55:45 +02001852 wlvif->bss_type = MAX_BSS_TYPE;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001853 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001854 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001855 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001856}
1857
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001858static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1859 struct ieee80211_vif *vif)
1860{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001861 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001862 struct wiphy *wiphy = hw->wiphy;
Eliad Peller536129c2011-10-05 11:55:45 +02001863 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001864 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001865 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001866 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02001867 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001868
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001869 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03001870 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001871
1872 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001873 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001874 wl1271_debug(DEBUG_MAC80211,
1875 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001876 ret = -EBUSY;
1877 goto out;
1878 }
Eliad Peller536129c2011-10-05 11:55:45 +02001879 wl12xx_init_vif_data(wlvif);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001880
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001881 /*
1882 * in some very corner case HW recovery scenarios its possible to
1883 * get here before __wl1271_op_remove_interface is complete, so
1884 * opt out if that is the case.
1885 */
1886 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1887 ret = -EBUSY;
1888 goto out;
1889 }
1890
Eliad Peller045c7452011-08-28 15:23:01 +03001891 switch (ieee80211_vif_type_p2p(vif)) {
1892 case NL80211_IFTYPE_P2P_CLIENT:
1893 wl->p2p = 1;
1894 /* fall-through */
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001895 case NL80211_IFTYPE_STATION:
Eliad Peller536129c2011-10-05 11:55:45 +02001896 wlvif->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001897 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001898 break;
1899 case NL80211_IFTYPE_ADHOC:
Eliad Peller536129c2011-10-05 11:55:45 +02001900 wlvif->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001901 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001902 break;
Eliad Peller045c7452011-08-28 15:23:01 +03001903 case NL80211_IFTYPE_P2P_GO:
1904 wl->p2p = 1;
1905 /* fall-through */
Arik Nemtsov038d9252010-10-16 21:53:24 +02001906 case NL80211_IFTYPE_AP:
Eliad Peller536129c2011-10-05 11:55:45 +02001907 wlvif->bss_type = BSS_TYPE_AP_BSS;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001908 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001909 default:
1910 ret = -EOPNOTSUPP;
1911 goto out;
1912 }
1913
Eliad Peller536129c2011-10-05 11:55:45 +02001914 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001915 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
1916 ret = -EINVAL;
1917 goto out;
1918 }
Eliad Peller784f6942011-10-05 11:55:39 +02001919 /*
1920 * we still need this in order to configure the fw
1921 * while uploading the nvs
1922 */
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001923 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001924
1925 if (wl->state != WL1271_STATE_OFF) {
1926 wl1271_error("cannot start because not in off state: %d",
1927 wl->state);
1928 ret = -EBUSY;
1929 goto out;
1930 }
1931
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001932 while (retries) {
1933 retries--;
1934 ret = wl1271_chip_wakeup(wl);
1935 if (ret < 0)
1936 goto power_off;
1937
1938 ret = wl1271_boot(wl);
1939 if (ret < 0)
1940 goto power_off;
1941
Eliad Peller92c77c72011-10-05 11:55:40 +02001942 ret = wl1271_hw_init(wl);
1943 if (ret < 0)
1944 goto irq_disable;
1945
Eliad Peller536129c2011-10-05 11:55:45 +02001946 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1947 wlvif->bss_type == BSS_TYPE_IBSS) {
Eliad Peller04e80792011-08-14 13:17:09 +03001948 /*
1949 * The device role is a special role used for
1950 * rx and tx frames prior to association (as
1951 * the STA role can get packets only from
1952 * its associated bssid)
1953 */
Eliad Peller784f6942011-10-05 11:55:39 +02001954 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller04e80792011-08-14 13:17:09 +03001955 WL1271_ROLE_DEVICE,
1956 &wl->dev_role_id);
1957 if (ret < 0)
1958 goto irq_disable;
1959 }
1960
Eliad Peller784f6942011-10-05 11:55:39 +02001961 ret = wl12xx_cmd_role_enable(wl, vif->addr,
1962 role_type, &wl->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001963 if (ret < 0)
1964 goto irq_disable;
1965
Eliad Peller92c77c72011-10-05 11:55:40 +02001966 ret = wl1271_init_vif_specific(wl, vif);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001967 if (ret < 0)
1968 goto irq_disable;
1969
Eliad Peller71125ab2010-10-28 21:46:43 +02001970 booted = true;
1971 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001972
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001973irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001974 mutex_unlock(&wl->mutex);
1975 /* Unlocking the mutex in the middle of handling is
1976 inherently unsafe. In this case we deem it safe to do,
1977 because we need to let any possibly pending IRQ out of
1978 the system (and while we are WL1271_STATE_OFF the IRQ
1979 work function will not do anything.) Also, any other
1980 possible concurrent operations will fail due to the
1981 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001982 wl1271_disable_interrupts(wl);
1983 wl1271_flush_deferred_work(wl);
1984 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001985 mutex_lock(&wl->mutex);
1986power_off:
1987 wl1271_power_off(wl);
1988 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989
Eliad Peller71125ab2010-10-28 21:46:43 +02001990 if (!booted) {
1991 wl1271_error("firmware boot failed despite %d retries",
1992 WL1271_BOOT_RETRIES);
1993 goto out;
1994 }
1995
1996 wl->vif = vif;
1997 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001998 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001999 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02002000
2001 /* update hw/fw version info in wiphy struct */
2002 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01002003 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02002004 sizeof(wiphy->fw_version));
2005
Luciano Coelhofb6a6812010-12-03 17:05:40 +02002006 /*
2007 * Now we know if 11a is supported (info from the NVS), so disable
2008 * 11a channels if not supported
2009 */
2010 if (!wl->enable_11a)
2011 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2012
2013 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2014 wl->enable_11a ? "" : "not ");
2015
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002016out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002017 mutex_unlock(&wl->mutex);
2018
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002019 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002020 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002021 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002022 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002023
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002024 return ret;
2025}
2026
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002027static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002028 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002029 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002030{
Eliad Peller536129c2011-10-05 11:55:45 +02002031 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002032 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002033
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002034 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002035
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002036 /* because of hardware recovery, we may get here twice */
2037 if (wl->state != WL1271_STATE_ON)
2038 return;
2039
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002040 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002041
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002042 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002043 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002044 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002045
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002046 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002047 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002048 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002049
Luciano Coelho08688d62010-07-08 17:50:07 +03002050 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002051 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002052 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002053 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002054 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002055 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002056 }
2057
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002058 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2059 /* disable active roles */
2060 ret = wl1271_ps_elp_wakeup(wl);
2061 if (ret < 0)
2062 goto deinit;
2063
Eliad Peller536129c2011-10-05 11:55:45 +02002064 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller04e80792011-08-14 13:17:09 +03002065 ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
2066 if (ret < 0)
2067 goto deinit;
2068 }
2069
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002070 ret = wl12xx_cmd_role_disable(wl, &wl->role_id);
2071 if (ret < 0)
2072 goto deinit;
2073
2074 wl1271_ps_elp_sleep(wl);
2075 }
2076deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002077 /* clear all hlids (except system_hlid) */
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002078 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002079 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002080 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
2081 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002082
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002083 /*
2084 * this must be before the cancel_work calls below, so that the work
2085 * functions don't perform further work.
2086 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002087 wl->state = WL1271_STATE_OFF;
2088
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002089 mutex_unlock(&wl->mutex);
2090
Ido Yariva6208652011-03-01 15:14:41 +02002091 wl1271_disable_interrupts(wl);
2092 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02002093 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02002094 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002095 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03002096 del_timer_sync(&wl->rx_streaming_timer);
2097 cancel_work_sync(&wl->rx_streaming_enable_work);
2098 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002099 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02002100 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002101
2102 mutex_lock(&wl->mutex);
2103
2104 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002105 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002106 wl1271_power_off(wl);
2107
Johannes Berg3b40c042011-07-13 10:39:16 +02002108 memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002109 wl->ssid_len = 0;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002110 wl->set_bss_type = MAX_BSS_TYPE;
Eliad Peller045c7452011-08-28 15:23:01 +03002111 wl->p2p = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002112 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002113
2114 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002115 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002116 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
2117 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002118 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002119 wl->tx_results_count = 0;
2120 wl->tx_packets_count = 0;
2121 wl->time_offset = 0;
2122 wl->session_counter = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03002123 wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
2124 wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002125 wl->vif = NULL;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002126 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002127 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002128 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02002129 wl->ap_fw_ps_map = 0;
2130 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002131 wl->sched_scanning = false;
Eliad Peller7f0979882011-08-14 13:17:06 +03002132 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002133 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerc690ec82011-08-14 13:17:07 +03002134 memset(wl->roles_map, 0, sizeof(wl->roles_map));
2135 memset(wl->links_map, 0, sizeof(wl->links_map));
Eliad Peller251c1772011-08-14 13:17:17 +03002136 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Arik Nemtsovda032092011-08-25 12:43:15 +03002137 wl->active_sta_count = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002138
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002139 /* The system link is always allocated */
2140 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
2141
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002142 /*
2143 * this is performed after the cancel_work calls and the associated
2144 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2145 * get executed before all these vars have been reset.
2146 */
2147 wl->flags = 0;
2148
Eliad Peller4d56ad92011-08-14 13:17:05 +03002149 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002150
Arik Nemtsov742246f2011-08-14 13:17:33 +03002151 for (i = 0; i < NUM_TX_QUEUES; i++) {
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002152 wl->tx_pkts_freed[i] = 0;
Arik Nemtsov742246f2011-08-14 13:17:33 +03002153 wl->tx_allocated_pkts[i] = 0;
2154 }
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002155
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002156 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002157
2158 kfree(wl->fw_status);
2159 wl->fw_status = NULL;
2160 kfree(wl->tx_res_if);
2161 wl->tx_res_if = NULL;
2162 kfree(wl->target_mem_map);
2163 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002164}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002165
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002166static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2167 struct ieee80211_vif *vif)
2168{
2169 struct wl1271 *wl = hw->priv;
2170
2171 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002172 /*
2173 * wl->vif can be null here if someone shuts down the interface
2174 * just when hardware recovery has been started.
2175 */
2176 if (wl->vif) {
2177 WARN_ON(wl->vif != vif);
Eliad Peller536129c2011-10-05 11:55:45 +02002178 __wl1271_op_remove_interface(wl, vif, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002179 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002180
Juuso Oikarinen67353292010-11-18 15:19:02 +02002181 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002182 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002183}
2184
Eliad Peller87fbcb02011-10-05 11:55:41 +02002185static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2186 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002187{
2188 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002189 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002190
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002191 /*
2192 * One of the side effects of the JOIN command is that is clears
2193 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2194 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002195 * Currently the only valid scenario for JOIN during association
2196 * is on roaming, in which case we will also be given new keys.
2197 * Keep the below message for now, unless it starts bothering
2198 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002199 */
2200 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2201 wl1271_info("JOIN while associated.");
2202
2203 if (set_assoc)
2204 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2205
Eliad Peller227e81e2011-08-14 13:17:26 +03002206 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002207 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002208 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002209 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002210 if (ret < 0)
2211 goto out;
2212
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002213 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2214 goto out;
2215
2216 /*
2217 * The join command disable the keep-alive mode, shut down its process,
2218 * and also clear the template config, so we need to reset it all after
2219 * the join. The acx_aid starts the keep-alive process, and the order
2220 * of the commands below is relevant.
2221 */
2222 ret = wl1271_acx_keep_alive_mode(wl, true);
2223 if (ret < 0)
2224 goto out;
2225
2226 ret = wl1271_acx_aid(wl, wl->aid);
2227 if (ret < 0)
2228 goto out;
2229
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002230 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002231 if (ret < 0)
2232 goto out;
2233
2234 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2235 ACX_KEEP_ALIVE_TPL_VALID);
2236 if (ret < 0)
2237 goto out;
2238
2239out:
2240 return ret;
2241}
2242
2243static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002244{
2245 int ret;
2246
Shahar Levi6d158ff2011-09-08 13:01:33 +03002247 if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags)) {
2248 wl12xx_cmd_stop_channel_switch(wl);
2249 ieee80211_chswitch_done(wl->vif, false);
2250 }
2251
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002252 /* to stop listening to a channel, we disconnect */
Eliad Pellerc690ec82011-08-14 13:17:07 +03002253 ret = wl12xx_cmd_role_stop_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002254 if (ret < 0)
2255 goto out;
2256
Oz Krakowskib992c682011-06-26 10:36:02 +03002257 /* reset TX security counters on a clean disconnect */
2258 wl->tx_security_last_seq_lsb = 0;
2259 wl->tx_security_seq = 0;
2260
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002261out:
2262 return ret;
2263}
2264
Eliad Peller87fbcb02011-10-05 11:55:41 +02002265static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002266{
Eliad Peller87fbcb02011-10-05 11:55:41 +02002267 wlvif->basic_rate_set = wl->bitrate_masks[wl->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002268 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002269}
2270
Eliad Peller251c1772011-08-14 13:17:17 +03002271static bool wl12xx_is_roc(struct wl1271 *wl)
2272{
2273 u8 role_id;
2274
2275 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2276 if (role_id >= WL12XX_MAX_ROLES)
2277 return false;
2278
2279 return true;
2280}
2281
Eliad Peller87fbcb02011-10-05 11:55:41 +02002282static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2283 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002284{
2285 int ret;
2286
2287 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002288 /* no need to croc if we weren't busy (e.g. during boot) */
2289 if (wl12xx_is_roc(wl)) {
2290 ret = wl12xx_croc(wl, wl->dev_role_id);
2291 if (ret < 0)
2292 goto out;
2293
2294 ret = wl12xx_cmd_role_stop_dev(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002295 if (ret < 0)
2296 goto out;
2297 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002298 wlvif->rate_set =
2299 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2300 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002301 if (ret < 0)
2302 goto out;
2303 ret = wl1271_acx_keep_alive_config(
2304 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2305 ACX_KEEP_ALIVE_TPL_INVALID);
2306 if (ret < 0)
2307 goto out;
2308 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2309 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002310 /* The current firmware only supports sched_scan in idle */
2311 if (wl->sched_scanning) {
2312 wl1271_scan_sched_scan_stop(wl);
2313 ieee80211_sched_scan_stopped(wl->hw);
2314 }
2315
Eliad Peller251c1772011-08-14 13:17:17 +03002316 ret = wl12xx_cmd_role_start_dev(wl);
2317 if (ret < 0)
2318 goto out;
2319
2320 ret = wl12xx_roc(wl, wl->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002321 if (ret < 0)
2322 goto out;
2323 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2324 }
2325
2326out:
2327 return ret;
2328}
2329
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002330static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2331{
2332 struct wl1271 *wl = hw->priv;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002333 struct ieee80211_vif *vif = wl->vif; /* TODO: reconfig all vifs */
2334 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002335 struct ieee80211_conf *conf = &hw->conf;
2336 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002337 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002338
2339 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2340
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002341 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2342 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002343 channel,
2344 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002345 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002346 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2347 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002348
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002349 /*
2350 * mac80211 will go to idle nearly immediately after transmitting some
2351 * frames, such as the deauth. To make sure those frames reach the air,
2352 * wait here until the TX queue is fully flushed.
2353 */
2354 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2355 (conf->flags & IEEE80211_CONF_IDLE))
2356 wl1271_tx_flush(wl);
2357
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002358 mutex_lock(&wl->mutex);
2359
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002360 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002361 /* we support configuring the channel and band while off */
2362 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2363 wl->band = conf->channel->band;
2364 wl->channel = channel;
2365 }
2366
Arik Nemtsov097f8822011-06-27 22:06:34 +03002367 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2368 wl->power_level = conf->power_level;
2369
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002370 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002371 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002372
Eliad Peller536129c2011-10-05 11:55:45 +02002373 is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002374
Ido Yariva6208652011-03-01 15:14:41 +02002375 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002376 if (ret < 0)
2377 goto out;
2378
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002379 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002380 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2381 ((wl->band != conf->channel->band) ||
2382 (wl->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002383 /* send all pending packets */
Eliad Peller536129c2011-10-05 11:55:45 +02002384 wl1271_tx_work_locked(wl, vif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002385 wl->band = conf->channel->band;
2386 wl->channel = channel;
2387
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002388 if (!is_ap) {
2389 /*
2390 * FIXME: the mac80211 should really provide a fixed
2391 * rate to use here. for now, just use the smallest
2392 * possible rate for the band as a fixed rate for
2393 * association frames and other control messages.
2394 */
2395 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002396 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002397
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002398 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002399 wl1271_tx_min_rate_get(wl,
2400 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002401 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002402 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002403 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002404 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002405
Eliad Peller251c1772011-08-14 13:17:17 +03002406 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2407 if (wl12xx_is_roc(wl)) {
2408 /* roaming */
2409 ret = wl12xx_croc(wl, wl->dev_role_id);
2410 if (ret < 0)
2411 goto out_sleep;
2412 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002413 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002414 if (ret < 0)
2415 wl1271_warning("cmd join on channel "
2416 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002417 } else {
2418 /*
2419 * change the ROC channel. do it only if we are
2420 * not idle. otherwise, CROC will be called
2421 * anyway.
2422 */
2423 if (wl12xx_is_roc(wl) &&
2424 !(conf->flags & IEEE80211_CONF_IDLE)) {
2425 ret = wl12xx_croc(wl, wl->dev_role_id);
2426 if (ret < 0)
2427 goto out_sleep;
2428
2429 ret = wl12xx_roc(wl, wl->dev_role_id);
2430 if (ret < 0)
2431 wl1271_warning("roc failed %d",
2432 ret);
2433 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002434 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002435 }
2436 }
2437
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002438 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002439 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002440 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002441 if (ret < 0)
2442 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002443 }
2444
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002445 /*
2446 * if mac80211 changes the PSM mode, make sure the mode is not
2447 * incorrectly changed after the pspoll failure active window.
2448 */
2449 if (changed & IEEE80211_CONF_CHANGE_PS)
2450 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2451
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002452 if (conf->flags & IEEE80211_CONF_PS &&
2453 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2454 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002455
2456 /*
2457 * We enter PSM only if we're already associated.
2458 * If we're not, we'll enter it when joining an SSID,
2459 * through the bss_info_changed() hook.
2460 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002461 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002462 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002463 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002464 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002465 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002466 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002467 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002468 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002469
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002470 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002471
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002472 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002473 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002474 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002475 }
2476
2477 if (conf->power_level != wl->power_level) {
2478 ret = wl1271_acx_tx_power(wl, conf->power_level);
2479 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002480 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002481
2482 wl->power_level = conf->power_level;
2483 }
2484
2485out_sleep:
2486 wl1271_ps_elp_sleep(wl);
2487
2488out:
2489 mutex_unlock(&wl->mutex);
2490
2491 return ret;
2492}
2493
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002494struct wl1271_filter_params {
2495 bool enabled;
2496 int mc_list_length;
2497 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2498};
2499
Jiri Pirko22bedad2010-04-01 21:22:57 +00002500static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2501 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002502{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002503 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002504 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002505 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002506
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002507 if (unlikely(wl->state == WL1271_STATE_OFF))
2508 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002509
Juuso Oikarinen74441132009-10-13 12:47:53 +03002510 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002511 if (!fp) {
2512 wl1271_error("Out of memory setting filters.");
2513 return 0;
2514 }
2515
2516 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002517 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002518 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2519 fp->enabled = false;
2520 } else {
2521 fp->enabled = true;
2522 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002523 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002524 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002525 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002526 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002527 }
2528
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002529 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002530}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002531
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002532#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2533 FIF_ALLMULTI | \
2534 FIF_FCSFAIL | \
2535 FIF_BCN_PRBRESP_PROMISC | \
2536 FIF_CONTROL | \
2537 FIF_OTHER_BSS)
2538
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002539static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2540 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002541 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002542{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002543 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002544 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002545 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
2546 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2547
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002548 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002549
Arik Nemtsov7d057862010-10-16 19:25:35 +02002550 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2551 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002552
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002553 mutex_lock(&wl->mutex);
2554
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002555 *total &= WL1271_SUPPORTED_FILTERS;
2556 changed &= WL1271_SUPPORTED_FILTERS;
2557
2558 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002559 goto out;
2560
Ido Yariva6208652011-03-01 15:14:41 +02002561 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002562 if (ret < 0)
2563 goto out;
2564
Eliad Peller536129c2011-10-05 11:55:45 +02002565 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
Arik Nemtsov7d057862010-10-16 19:25:35 +02002566 if (*total & FIF_ALLMULTI)
2567 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2568 else if (fp)
2569 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2570 fp->mc_list,
2571 fp->mc_list_length);
2572 if (ret < 0)
2573 goto out_sleep;
2574 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002575
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002576 /*
2577 * the fw doesn't provide an api to configure the filters. instead,
2578 * the filters configuration is based on the active roles / ROC
2579 * state.
2580 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002581
2582out_sleep:
2583 wl1271_ps_elp_sleep(wl);
2584
2585out:
2586 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002587 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002588}
2589
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002590static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2591 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2592 u16 tx_seq_16)
2593{
2594 struct wl1271_ap_key *ap_key;
2595 int i;
2596
2597 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2598
2599 if (key_size > MAX_KEY_SIZE)
2600 return -EINVAL;
2601
2602 /*
2603 * Find next free entry in ap_keys. Also check we are not replacing
2604 * an existing key.
2605 */
2606 for (i = 0; i < MAX_NUM_KEYS; i++) {
2607 if (wl->recorded_ap_keys[i] == NULL)
2608 break;
2609
2610 if (wl->recorded_ap_keys[i]->id == id) {
2611 wl1271_warning("trying to record key replacement");
2612 return -EINVAL;
2613 }
2614 }
2615
2616 if (i == MAX_NUM_KEYS)
2617 return -EBUSY;
2618
2619 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2620 if (!ap_key)
2621 return -ENOMEM;
2622
2623 ap_key->id = id;
2624 ap_key->key_type = key_type;
2625 ap_key->key_size = key_size;
2626 memcpy(ap_key->key, key, key_size);
2627 ap_key->hlid = hlid;
2628 ap_key->tx_seq_32 = tx_seq_32;
2629 ap_key->tx_seq_16 = tx_seq_16;
2630
2631 wl->recorded_ap_keys[i] = ap_key;
2632 return 0;
2633}
2634
2635static void wl1271_free_ap_keys(struct wl1271 *wl)
2636{
2637 int i;
2638
2639 for (i = 0; i < MAX_NUM_KEYS; i++) {
2640 kfree(wl->recorded_ap_keys[i]);
2641 wl->recorded_ap_keys[i] = NULL;
2642 }
2643}
2644
2645static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2646{
2647 int i, ret = 0;
2648 struct wl1271_ap_key *key;
2649 bool wep_key_added = false;
2650
2651 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002652 u8 hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002653 if (wl->recorded_ap_keys[i] == NULL)
2654 break;
2655
2656 key = wl->recorded_ap_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002657 hlid = key->hlid;
2658 if (hlid == WL12XX_INVALID_LINK_ID)
2659 hlid = wl->ap_bcast_hlid;
2660
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002661 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2662 key->id, key->key_type,
2663 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002664 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002665 key->tx_seq_16);
2666 if (ret < 0)
2667 goto out;
2668
2669 if (key->key_type == KEY_WEP)
2670 wep_key_added = true;
2671 }
2672
2673 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002674 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002675 wl->ap_bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002676 if (ret < 0)
2677 goto out;
2678 }
2679
2680out:
2681 wl1271_free_ap_keys(wl);
2682 return ret;
2683}
2684
Eliad Peller536129c2011-10-05 11:55:45 +02002685static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2686 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002687 u8 key_size, const u8 *key, u32 tx_seq_32,
2688 u16 tx_seq_16, struct ieee80211_sta *sta)
2689{
2690 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002691 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002692
2693 if (is_ap) {
2694 struct wl1271_station *wl_sta;
2695 u8 hlid;
2696
2697 if (sta) {
2698 wl_sta = (struct wl1271_station *)sta->drv_priv;
2699 hlid = wl_sta->hlid;
2700 } else {
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002701 hlid = wl->ap_bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002702 }
2703
2704 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2705 /*
2706 * We do not support removing keys after AP shutdown.
2707 * Pretend we do to make mac80211 happy.
2708 */
2709 if (action != KEY_ADD_OR_REPLACE)
2710 return 0;
2711
2712 ret = wl1271_record_ap_key(wl, id,
2713 key_type, key_size,
2714 key, hlid, tx_seq_32,
2715 tx_seq_16);
2716 } else {
2717 ret = wl1271_cmd_set_ap_key(wl, action,
2718 id, key_type, key_size,
2719 key, hlid, tx_seq_32,
2720 tx_seq_16);
2721 }
2722
2723 if (ret < 0)
2724 return ret;
2725 } else {
2726 const u8 *addr;
2727 static const u8 bcast_addr[ETH_ALEN] = {
2728 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2729 };
2730
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002731 /*
2732 * A STA set to GEM cipher requires 2 tx spare blocks.
2733 * Return to default value when GEM cipher key is removed
2734 */
2735 if (key_type == KEY_GEM) {
2736 if (action == KEY_ADD_OR_REPLACE)
2737 wl->tx_spare_blocks = 2;
2738 else if (action == KEY_REMOVE)
2739 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2740 }
2741
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002742 addr = sta ? sta->addr : bcast_addr;
2743
2744 if (is_zero_ether_addr(addr)) {
2745 /* We dont support TX only encryption */
2746 return -EOPNOTSUPP;
2747 }
2748
2749 /* The wl1271 does not allow to remove unicast keys - they
2750 will be cleared automatically on next CMD_JOIN. Ignore the
2751 request silently, as we dont want the mac80211 to emit
2752 an error message. */
2753 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2754 return 0;
2755
Eliad Peller010d3d32011-08-14 13:17:31 +03002756 /* don't remove key if hlid was already deleted */
2757 if (action == KEY_REMOVE &&
2758 wl->sta_hlid == WL12XX_INVALID_LINK_ID)
2759 return 0;
2760
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002761 ret = wl1271_cmd_set_sta_key(wl, action,
2762 id, key_type, key_size,
2763 key, addr, tx_seq_32,
2764 tx_seq_16);
2765 if (ret < 0)
2766 return ret;
2767
2768 /* the default WEP key needs to be configured at least once */
2769 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002770 ret = wl12xx_cmd_set_default_wep_key(wl,
2771 wl->default_key,
2772 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002773 if (ret < 0)
2774 return ret;
2775 }
2776 }
2777
2778 return 0;
2779}
2780
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002781static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2782 struct ieee80211_vif *vif,
2783 struct ieee80211_sta *sta,
2784 struct ieee80211_key_conf *key_conf)
2785{
2786 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002787 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002788 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002789 u32 tx_seq_32 = 0;
2790 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002791 u8 key_type;
2792
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002793 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2794
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002795 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002796 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002797 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002798 key_conf->keylen, key_conf->flags);
2799 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2800
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002801 mutex_lock(&wl->mutex);
2802
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002803 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2804 ret = -EAGAIN;
2805 goto out_unlock;
2806 }
2807
Ido Yariva6208652011-03-01 15:14:41 +02002808 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002809 if (ret < 0)
2810 goto out_unlock;
2811
Johannes Berg97359d12010-08-10 09:46:38 +02002812 switch (key_conf->cipher) {
2813 case WLAN_CIPHER_SUITE_WEP40:
2814 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002815 key_type = KEY_WEP;
2816
2817 key_conf->hw_key_idx = key_conf->keyidx;
2818 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002819 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002820 key_type = KEY_TKIP;
2821
2822 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002823 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2824 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002825 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002826 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002827 key_type = KEY_AES;
2828
2829 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002830 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2831 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002832 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002833 case WL1271_CIPHER_SUITE_GEM:
2834 key_type = KEY_GEM;
2835 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2836 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2837 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002838 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002839 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002840
2841 ret = -EOPNOTSUPP;
2842 goto out_sleep;
2843 }
2844
2845 switch (cmd) {
2846 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002847 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002848 key_conf->keyidx, key_type,
2849 key_conf->keylen, key_conf->key,
2850 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002851 if (ret < 0) {
2852 wl1271_error("Could not add or replace key");
2853 goto out_sleep;
2854 }
2855 break;
2856
2857 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002858 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002859 key_conf->keyidx, key_type,
2860 key_conf->keylen, key_conf->key,
2861 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002862 if (ret < 0) {
2863 wl1271_error("Could not remove key");
2864 goto out_sleep;
2865 }
2866 break;
2867
2868 default:
2869 wl1271_error("Unsupported key cmd 0x%x", cmd);
2870 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002871 break;
2872 }
2873
2874out_sleep:
2875 wl1271_ps_elp_sleep(wl);
2876
2877out_unlock:
2878 mutex_unlock(&wl->mutex);
2879
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002880 return ret;
2881}
2882
2883static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002884 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002885 struct cfg80211_scan_request *req)
2886{
2887 struct wl1271 *wl = hw->priv;
2888 int ret;
2889 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002890 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002891
2892 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2893
2894 if (req->n_ssids) {
2895 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002896 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002897 }
2898
2899 mutex_lock(&wl->mutex);
2900
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002901 if (wl->state == WL1271_STATE_OFF) {
2902 /*
2903 * We cannot return -EBUSY here because cfg80211 will expect
2904 * a call to ieee80211_scan_completed if we do - in this case
2905 * there won't be any call.
2906 */
2907 ret = -EAGAIN;
2908 goto out;
2909 }
2910
Ido Yariva6208652011-03-01 15:14:41 +02002911 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002912 if (ret < 0)
2913 goto out;
2914
Eliad Peller251c1772011-08-14 13:17:17 +03002915 /* cancel ROC before scanning */
2916 if (wl12xx_is_roc(wl)) {
2917 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2918 /* don't allow scanning right now */
2919 ret = -EBUSY;
2920 goto out_sleep;
2921 }
2922 wl12xx_croc(wl, wl->dev_role_id);
2923 wl12xx_cmd_role_stop_dev(wl);
2924 }
2925
Eliad Peller784f6942011-10-05 11:55:39 +02002926 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002927out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002928 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002929out:
2930 mutex_unlock(&wl->mutex);
2931
2932 return ret;
2933}
2934
Eliad Peller73ecce32011-06-27 13:06:45 +03002935static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2936 struct ieee80211_vif *vif)
2937{
2938 struct wl1271 *wl = hw->priv;
2939 int ret;
2940
2941 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2942
2943 mutex_lock(&wl->mutex);
2944
2945 if (wl->state == WL1271_STATE_OFF)
2946 goto out;
2947
2948 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2949 goto out;
2950
2951 ret = wl1271_ps_elp_wakeup(wl);
2952 if (ret < 0)
2953 goto out;
2954
2955 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2956 ret = wl1271_scan_stop(wl);
2957 if (ret < 0)
2958 goto out_sleep;
2959 }
2960 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2961 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002962 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03002963 wl->scan.req = NULL;
2964 ieee80211_scan_completed(wl->hw, true);
2965
2966out_sleep:
2967 wl1271_ps_elp_sleep(wl);
2968out:
2969 mutex_unlock(&wl->mutex);
2970
2971 cancel_delayed_work_sync(&wl->scan_complete_work);
2972}
2973
Luciano Coelho33c2c062011-05-10 14:46:02 +03002974static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2975 struct ieee80211_vif *vif,
2976 struct cfg80211_sched_scan_request *req,
2977 struct ieee80211_sched_scan_ies *ies)
2978{
2979 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002980 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03002981 int ret;
2982
2983 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2984
2985 mutex_lock(&wl->mutex);
2986
2987 ret = wl1271_ps_elp_wakeup(wl);
2988 if (ret < 0)
2989 goto out;
2990
Eliad Peller536129c2011-10-05 11:55:45 +02002991 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03002992 if (ret < 0)
2993 goto out_sleep;
2994
Eliad Peller536129c2011-10-05 11:55:45 +02002995 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03002996 if (ret < 0)
2997 goto out_sleep;
2998
2999 wl->sched_scanning = true;
3000
3001out_sleep:
3002 wl1271_ps_elp_sleep(wl);
3003out:
3004 mutex_unlock(&wl->mutex);
3005 return ret;
3006}
3007
3008static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3009 struct ieee80211_vif *vif)
3010{
3011 struct wl1271 *wl = hw->priv;
3012 int ret;
3013
3014 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3015
3016 mutex_lock(&wl->mutex);
3017
3018 ret = wl1271_ps_elp_wakeup(wl);
3019 if (ret < 0)
3020 goto out;
3021
3022 wl1271_scan_sched_scan_stop(wl);
3023
3024 wl1271_ps_elp_sleep(wl);
3025out:
3026 mutex_unlock(&wl->mutex);
3027}
3028
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003029static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3030{
3031 struct wl1271 *wl = hw->priv;
3032 int ret = 0;
3033
3034 mutex_lock(&wl->mutex);
3035
3036 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3037 ret = -EAGAIN;
3038 goto out;
3039 }
3040
Ido Yariva6208652011-03-01 15:14:41 +02003041 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003042 if (ret < 0)
3043 goto out;
3044
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003045 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003046 if (ret < 0)
3047 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3048
3049 wl1271_ps_elp_sleep(wl);
3050
3051out:
3052 mutex_unlock(&wl->mutex);
3053
3054 return ret;
3055}
3056
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003057static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3058{
3059 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003060 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003061
3062 mutex_lock(&wl->mutex);
3063
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003064 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3065 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003066 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003067 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003068
Ido Yariva6208652011-03-01 15:14:41 +02003069 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003070 if (ret < 0)
3071 goto out;
3072
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003073 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003074 if (ret < 0)
3075 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
3076
3077 wl1271_ps_elp_sleep(wl);
3078
3079out:
3080 mutex_unlock(&wl->mutex);
3081
3082 return ret;
3083}
3084
Arik Nemtsove78a2872010-10-16 19:07:21 +02003085static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003086 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003087{
Eliad Peller889cb362011-05-01 09:56:45 +03003088 u8 ssid_len;
3089 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3090 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003091
Eliad Peller889cb362011-05-01 09:56:45 +03003092 if (!ptr) {
3093 wl1271_error("No SSID in IEs!");
3094 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003095 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003096
Eliad Peller889cb362011-05-01 09:56:45 +03003097 ssid_len = ptr[1];
3098 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3099 wl1271_error("SSID is too long!");
3100 return -EINVAL;
3101 }
3102
3103 wl->ssid_len = ssid_len;
3104 memcpy(wl->ssid, ptr+2, ssid_len);
3105 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003106}
3107
Eliad Pellerd48055d2011-09-15 12:07:04 +03003108static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3109{
3110 int len;
3111 const u8 *next, *end = skb->data + skb->len;
3112 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3113 skb->len - ieoffset);
3114 if (!ie)
3115 return;
3116 len = ie[1] + 2;
3117 next = ie + len;
3118 memmove(ie, next, end - next);
3119 skb_trim(skb, skb->len - len);
3120}
3121
Eliad Peller26b4bf22011-09-15 12:07:05 +03003122static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3123 unsigned int oui, u8 oui_type,
3124 int ieoffset)
3125{
3126 int len;
3127 const u8 *next, *end = skb->data + skb->len;
3128 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3129 skb->data + ieoffset,
3130 skb->len - ieoffset);
3131 if (!ie)
3132 return;
3133 len = ie[1] + 2;
3134 next = ie + len;
3135 memmove(ie, next, end - next);
3136 skb_trim(skb, skb->len - len);
3137}
3138
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003139static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
3140 u8 *probe_rsp_data,
3141 size_t probe_rsp_len,
3142 u32 rates)
3143{
3144 struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
3145 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3146 int ssid_ie_offset, ie_offset, templ_len;
3147 const u8 *ptr;
3148
3149 /* no need to change probe response if the SSID is set correctly */
3150 if (wl->ssid_len > 0)
3151 return wl1271_cmd_template_set(wl,
3152 CMD_TEMPL_AP_PROBE_RESPONSE,
3153 probe_rsp_data,
3154 probe_rsp_len, 0,
3155 rates);
3156
3157 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3158 wl1271_error("probe_rsp template too big");
3159 return -EINVAL;
3160 }
3161
3162 /* start searching from IE offset */
3163 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3164
3165 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3166 probe_rsp_len - ie_offset);
3167 if (!ptr) {
3168 wl1271_error("No SSID in beacon!");
3169 return -EINVAL;
3170 }
3171
3172 ssid_ie_offset = ptr - probe_rsp_data;
3173 ptr += (ptr[1] + 2);
3174
3175 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3176
3177 /* insert SSID from bss_conf */
3178 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3179 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3180 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3181 bss_conf->ssid, bss_conf->ssid_len);
3182 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3183
3184 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3185 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3186 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3187
3188 return wl1271_cmd_template_set(wl,
3189 CMD_TEMPL_AP_PROBE_RESPONSE,
3190 probe_rsp_templ,
3191 templ_len, 0,
3192 rates);
3193}
3194
Arik Nemtsove78a2872010-10-16 19:07:21 +02003195static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
3196 struct ieee80211_bss_conf *bss_conf,
3197 u32 changed)
3198{
3199 int ret = 0;
3200
3201 if (changed & BSS_CHANGED_ERP_SLOT) {
3202 if (bss_conf->use_short_slot)
3203 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
3204 else
3205 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
3206 if (ret < 0) {
3207 wl1271_warning("Set slot time failed %d", ret);
3208 goto out;
3209 }
3210 }
3211
3212 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3213 if (bss_conf->use_short_preamble)
3214 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
3215 else
3216 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
3217 }
3218
3219 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3220 if (bss_conf->use_cts_prot)
3221 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
3222 else
3223 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
3224 if (ret < 0) {
3225 wl1271_warning("Set ctsprotect failed %d", ret);
3226 goto out;
3227 }
3228 }
3229
3230out:
3231 return ret;
3232}
3233
3234static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3235 struct ieee80211_vif *vif,
3236 struct ieee80211_bss_conf *bss_conf,
3237 u32 changed)
3238{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003239 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003240 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003241 int ret = 0;
3242
3243 if ((changed & BSS_CHANGED_BEACON_INT)) {
3244 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3245 bss_conf->beacon_int);
3246
3247 wl->beacon_int = bss_conf->beacon_int;
3248 }
3249
3250 if ((changed & BSS_CHANGED_BEACON)) {
3251 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003252 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003253 int ieoffset = offsetof(struct ieee80211_mgmt,
3254 u.beacon.variable);
3255 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3256 u16 tmpl_id;
3257
3258 if (!beacon)
3259 goto out;
3260
3261 wl1271_debug(DEBUG_MASTER, "beacon updated");
3262
3263 ret = wl1271_ssid_set(wl, beacon, ieoffset);
3264 if (ret < 0) {
3265 dev_kfree_skb(beacon);
3266 goto out;
3267 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003268 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003269 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3270 CMD_TEMPL_BEACON;
3271 ret = wl1271_cmd_template_set(wl, tmpl_id,
3272 beacon->data,
3273 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003274 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003275 if (ret < 0) {
3276 dev_kfree_skb(beacon);
3277 goto out;
3278 }
3279
Eliad Pellerd48055d2011-09-15 12:07:04 +03003280 /* remove TIM ie from probe response */
3281 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3282
Eliad Peller26b4bf22011-09-15 12:07:05 +03003283 /*
3284 * remove p2p ie from probe response.
3285 * the fw reponds to probe requests that don't include
3286 * the p2p ie. probe requests with p2p ie will be passed,
3287 * and will be responded by the supplicant (the spec
3288 * forbids including the p2p ie when responding to probe
3289 * requests that didn't include it).
3290 */
3291 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3292 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3293
Arik Nemtsove78a2872010-10-16 19:07:21 +02003294 hdr = (struct ieee80211_hdr *) beacon->data;
3295 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3296 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003297 if (is_ap)
3298 ret = wl1271_ap_set_probe_resp_tmpl(wl,
3299 beacon->data,
3300 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003301 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003302 else
3303 ret = wl1271_cmd_template_set(wl,
3304 CMD_TEMPL_PROBE_RESPONSE,
3305 beacon->data,
3306 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003307 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003308 dev_kfree_skb(beacon);
3309 if (ret < 0)
3310 goto out;
3311 }
3312
3313out:
3314 return ret;
3315}
3316
3317/* AP mode changes */
3318static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003319 struct ieee80211_vif *vif,
3320 struct ieee80211_bss_conf *bss_conf,
3321 u32 changed)
3322{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003323 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003324 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003325
Arik Nemtsove78a2872010-10-16 19:07:21 +02003326 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3327 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003328
Eliad Peller87fbcb02011-10-05 11:55:41 +02003329 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003330 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003331 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003332 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003333
Eliad Peller87fbcb02011-10-05 11:55:41 +02003334 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003335 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003336 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003337 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003338 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003339
Eliad Peller784f6942011-10-05 11:55:39 +02003340 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003341 if (ret < 0)
3342 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003343 }
3344
Arik Nemtsove78a2872010-10-16 19:07:21 +02003345 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3346 if (ret < 0)
3347 goto out;
3348
3349 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3350 if (bss_conf->enable_beacon) {
3351 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003352 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003353 if (ret < 0)
3354 goto out;
3355
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003356 ret = wl1271_ap_init_hwenc(wl);
3357 if (ret < 0)
3358 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003359
3360 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3361 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003362 }
3363 } else {
3364 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003365 ret = wl12xx_cmd_role_stop_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003366 if (ret < 0)
3367 goto out;
3368
3369 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3370 wl1271_debug(DEBUG_AP, "stopped AP");
3371 }
3372 }
3373 }
3374
3375 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3376 if (ret < 0)
3377 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003378
3379 /* Handle HT information change */
3380 if ((changed & BSS_CHANGED_HT) &&
3381 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3382 ret = wl1271_acx_set_ht_information(wl,
3383 bss_conf->ht_operation_mode);
3384 if (ret < 0) {
3385 wl1271_warning("Set ht information failed %d", ret);
3386 goto out;
3387 }
3388 }
3389
Arik Nemtsove78a2872010-10-16 19:07:21 +02003390out:
3391 return;
3392}
3393
3394/* STA/IBSS mode changes */
3395static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3396 struct ieee80211_vif *vif,
3397 struct ieee80211_bss_conf *bss_conf,
3398 u32 changed)
3399{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003400 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003401 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003402 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003403 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003404 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003405 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003406 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003407 bool sta_exists = false;
3408 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003409
3410 if (is_ibss) {
3411 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3412 changed);
3413 if (ret < 0)
3414 goto out;
3415 }
3416
Eliad Peller227e81e2011-08-14 13:17:26 +03003417 if (changed & BSS_CHANGED_IBSS) {
3418 if (bss_conf->ibss_joined) {
3419 set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
3420 ibss_joined = true;
3421 } else {
3422 if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
3423 &wl->flags)) {
3424 wl1271_unjoin(wl);
3425 wl12xx_cmd_role_start_dev(wl);
3426 wl12xx_roc(wl, wl->dev_role_id);
3427 }
3428 }
3429 }
3430
3431 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003432 do_join = true;
3433
3434 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003435 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003436 do_join = true;
3437
Eliad Peller227e81e2011-08-14 13:17:26 +03003438 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003439 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3440 bss_conf->enable_beacon ? "enabled" : "disabled");
3441
3442 if (bss_conf->enable_beacon)
3443 wl->set_bss_type = BSS_TYPE_IBSS;
3444 else
3445 wl->set_bss_type = BSS_TYPE_STA_BSS;
3446 do_join = true;
3447 }
3448
Arik Nemtsove78a2872010-10-16 19:07:21 +02003449 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003450 bool enable = false;
3451 if (bss_conf->cqm_rssi_thold)
3452 enable = true;
3453 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3454 bss_conf->cqm_rssi_thold,
3455 bss_conf->cqm_rssi_hyst);
3456 if (ret < 0)
3457 goto out;
3458 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3459 }
3460
Eliad Pellercdf09492011-10-05 11:55:44 +02003461 if (changed & BSS_CHANGED_BSSID)
3462 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003463 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003464 if (ret < 0)
3465 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003466
Eliad Peller784f6942011-10-05 11:55:39 +02003467 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003468 if (ret < 0)
3469 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003470
Eliad Pellerfa287b82010-12-26 09:27:50 +01003471 /* Need to update the BSSID (for filtering etc) */
3472 do_join = true;
3473 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003474
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003475 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3476 rcu_read_lock();
3477 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3478 if (!sta)
3479 goto sta_not_found;
3480
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003481 /* save the supp_rates of the ap */
3482 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3483 if (sta->ht_cap.ht_supported)
3484 sta_rate_set |=
3485 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003486 sta_ht_cap = sta->ht_cap;
3487 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003488
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003489sta_not_found:
3490 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003491 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003492
Arik Nemtsove78a2872010-10-16 19:07:21 +02003493 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003494 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003495 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003496 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003497 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003498 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003499
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003500 wl->ps_poll_failures = 0;
3501
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003502 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003503 * use basic rates from AP, and determine lowest rate
3504 * to use with control frames.
3505 */
3506 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003507 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003508 wl1271_tx_enabled_rates_get(wl, rates,
3509 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003510 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003511 wl1271_tx_min_rate_get(wl,
3512 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003513 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003514 wlvif->rate_set =
3515 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003516 sta_rate_set,
3517 wl->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003518 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003519 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003520 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003521
3522 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003523 * with wl1271, we don't need to update the
3524 * beacon_int and dtim_period, because the firmware
3525 * updates it by itself when the first beacon is
3526 * received after a join.
3527 */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003528 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wl->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003529 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003530 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003531
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003532 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003533 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003534 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003535 dev_kfree_skb(wl->probereq);
3536 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3537 ieoffset = offsetof(struct ieee80211_mgmt,
3538 u.probe_req.variable);
3539 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003540
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003541 /* enable the connection monitoring feature */
3542 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003543 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003544 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003545 } else {
3546 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003547 bool was_assoc =
3548 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3549 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003550 bool was_ifup =
3551 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3552 &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003553 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003554
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003555 /* free probe-request template */
3556 dev_kfree_skb(wl->probereq);
3557 wl->probereq = NULL;
3558
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003559 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003560 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003561
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003562 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003563 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003564 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003565 wl1271_tx_min_rate_get(wl,
3566 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003567 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003568 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003569 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003570
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003571 /* disable connection monitor features */
3572 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003573
3574 /* Disable the keep-alive feature */
3575 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003576 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003577 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003578
3579 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003580 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003581 u32 conf_flags = wl->hw->conf.flags;
3582 /*
3583 * we might have to disable roc, if there was
3584 * no IF_OPER_UP notification.
3585 */
3586 if (!was_ifup) {
3587 ret = wl12xx_croc(wl, wl->role_id);
3588 if (ret < 0)
3589 goto out;
3590 }
3591 /*
3592 * (we also need to disable roc in case of
3593 * roaming on the same channel. until we will
3594 * have a better flow...)
3595 */
3596 if (test_bit(wl->dev_role_id, wl->roc_map)) {
3597 ret = wl12xx_croc(wl, wl->dev_role_id);
3598 if (ret < 0)
3599 goto out;
3600 }
3601
Eliad Peller30df14d2011-04-05 19:13:28 +03003602 wl1271_unjoin(wl);
Eliad Peller251c1772011-08-14 13:17:17 +03003603 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
3604 wl12xx_cmd_role_start_dev(wl);
3605 wl12xx_roc(wl, wl->dev_role_id);
3606 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003607 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003608 }
3609 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003610
Eliad Pellerd192d262011-05-24 14:33:08 +03003611 if (changed & BSS_CHANGED_IBSS) {
3612 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3613 bss_conf->ibss_joined);
3614
3615 if (bss_conf->ibss_joined) {
3616 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003617 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003618 wl1271_tx_enabled_rates_get(wl, rates,
3619 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003620 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003621 wl1271_tx_min_rate_get(wl,
3622 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003623
Shahar Levi06b660e2011-09-05 13:54:36 +03003624 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003625 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3626 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003627 if (ret < 0)
3628 goto out;
3629 }
3630 }
3631
Arik Nemtsove78a2872010-10-16 19:07:21 +02003632 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3633 if (ret < 0)
3634 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003635
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003636 if (changed & BSS_CHANGED_ARP_FILTER) {
3637 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003638 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003639
Eliad Pellerc5312772010-12-09 11:31:27 +02003640 if (bss_conf->arp_addr_cnt == 1 &&
3641 bss_conf->arp_filter_enabled) {
3642 /*
3643 * The template should have been configured only upon
3644 * association. however, it seems that the correct ip
3645 * isn't being set (when sending), so we have to
3646 * reconfigure the template upon every ip change.
3647 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003648 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003649 if (ret < 0) {
3650 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003651 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003652 }
3653
3654 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003655 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003656 addr);
3657 } else
3658 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003659
3660 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003661 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003662 }
3663
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003664 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003665 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003666 if (ret < 0) {
3667 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003668 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003669 }
Eliad Peller251c1772011-08-14 13:17:17 +03003670
3671 /* ROC until connected (after EAPOL exchange) */
3672 if (!is_ibss) {
3673 ret = wl12xx_roc(wl, wl->role_id);
3674 if (ret < 0)
3675 goto out;
3676
3677 wl1271_check_operstate(wl,
3678 ieee80211_get_operstate(vif));
3679 }
3680 /*
3681 * stop device role if started (we might already be in
3682 * STA role). TODO: make it better.
3683 */
3684 if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3685 ret = wl12xx_croc(wl, wl->dev_role_id);
3686 if (ret < 0)
3687 goto out;
3688
3689 ret = wl12xx_cmd_role_stop_dev(wl);
3690 if (ret < 0)
3691 goto out;
3692 }
Eliad Peller05dba352011-08-23 16:37:01 +03003693
3694 /* If we want to go in PSM but we're not there yet */
3695 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3696 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
3697 enum wl1271_cmd_ps_mode mode;
3698
3699 mode = STATION_POWER_SAVE_MODE;
3700 ret = wl1271_ps_set_mode(wl, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003701 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003702 true);
3703 if (ret < 0)
3704 goto out;
3705 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003706 }
3707
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003708 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003709 if (sta_exists) {
3710 if ((changed & BSS_CHANGED_HT) &&
3711 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003712 ret = wl1271_acx_set_ht_capabilities(wl,
3713 &sta_ht_cap,
3714 true,
3715 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003716 if (ret < 0) {
3717 wl1271_warning("Set ht cap true failed %d",
3718 ret);
3719 goto out;
3720 }
3721 }
3722 /* handle new association without HT and disassociation */
3723 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003724 ret = wl1271_acx_set_ht_capabilities(wl,
3725 &sta_ht_cap,
3726 false,
3727 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003728 if (ret < 0) {
3729 wl1271_warning("Set ht cap false failed %d",
3730 ret);
3731 goto out;
3732 }
3733 }
3734 }
3735
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003736 /* Handle HT information change. Done after join. */
3737 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003738 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3739 ret = wl1271_acx_set_ht_information(wl,
3740 bss_conf->ht_operation_mode);
3741 if (ret < 0) {
3742 wl1271_warning("Set ht information failed %d", ret);
3743 goto out;
3744 }
3745 }
3746
Arik Nemtsove78a2872010-10-16 19:07:21 +02003747out:
3748 return;
3749}
3750
3751static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3752 struct ieee80211_vif *vif,
3753 struct ieee80211_bss_conf *bss_conf,
3754 u32 changed)
3755{
3756 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003757 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3758 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003759 int ret;
3760
3761 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3762 (int)changed);
3763
3764 mutex_lock(&wl->mutex);
3765
3766 if (unlikely(wl->state == WL1271_STATE_OFF))
3767 goto out;
3768
Ido Yariva6208652011-03-01 15:14:41 +02003769 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003770 if (ret < 0)
3771 goto out;
3772
3773 if (is_ap)
3774 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3775 else
3776 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3777
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003778 wl1271_ps_elp_sleep(wl);
3779
3780out:
3781 mutex_unlock(&wl->mutex);
3782}
3783
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003784static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3785 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003786 const struct ieee80211_tx_queue_params *params)
3787{
3788 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003789 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003790 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003791
3792 mutex_lock(&wl->mutex);
3793
3794 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3795
Kalle Valo4695dc92010-03-18 12:26:38 +02003796 if (params->uapsd)
3797 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3798 else
3799 ps_scheme = CONF_PS_SCHEME_LEGACY;
3800
Arik Nemtsov488fc542010-10-16 20:33:45 +02003801 if (wl->state == WL1271_STATE_OFF) {
3802 /*
3803 * If the state is off, the parameters will be recorded and
3804 * configured on init. This happens in AP-mode.
3805 */
3806 struct conf_tx_ac_category *conf_ac =
3807 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3808 struct conf_tx_tid *conf_tid =
3809 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3810
3811 conf_ac->ac = wl1271_tx_get_queue(queue);
3812 conf_ac->cw_min = (u8)params->cw_min;
3813 conf_ac->cw_max = params->cw_max;
3814 conf_ac->aifsn = params->aifs;
3815 conf_ac->tx_op_limit = params->txop << 5;
3816
3817 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3818 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3819 conf_tid->tsid = wl1271_tx_get_queue(queue);
3820 conf_tid->ps_scheme = ps_scheme;
3821 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3822 conf_tid->apsd_conf[0] = 0;
3823 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003824 goto out;
3825 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003826
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003827 ret = wl1271_ps_elp_wakeup(wl);
3828 if (ret < 0)
3829 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003830
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003831 /*
3832 * the txop is confed in units of 32us by the mac80211,
3833 * we need us
3834 */
3835 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3836 params->cw_min, params->cw_max,
3837 params->aifs, params->txop << 5);
3838 if (ret < 0)
3839 goto out_sleep;
3840
3841 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3842 CONF_CHANNEL_TYPE_EDCF,
3843 wl1271_tx_get_queue(queue),
3844 ps_scheme, CONF_ACK_POLICY_LEGACY,
3845 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003846
3847out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003848 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003849
3850out:
3851 mutex_unlock(&wl->mutex);
3852
3853 return ret;
3854}
3855
Eliad Peller37a41b42011-09-21 14:06:11 +03003856static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
3857 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003858{
3859
3860 struct wl1271 *wl = hw->priv;
3861 u64 mactime = ULLONG_MAX;
3862 int ret;
3863
3864 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3865
3866 mutex_lock(&wl->mutex);
3867
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003868 if (unlikely(wl->state == WL1271_STATE_OFF))
3869 goto out;
3870
Ido Yariva6208652011-03-01 15:14:41 +02003871 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003872 if (ret < 0)
3873 goto out;
3874
3875 ret = wl1271_acx_tsf_info(wl, &mactime);
3876 if (ret < 0)
3877 goto out_sleep;
3878
3879out_sleep:
3880 wl1271_ps_elp_sleep(wl);
3881
3882out:
3883 mutex_unlock(&wl->mutex);
3884 return mactime;
3885}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003886
John W. Linvilleece550d2010-07-28 16:41:06 -04003887static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3888 struct survey_info *survey)
3889{
3890 struct wl1271 *wl = hw->priv;
3891 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003892
John W. Linvilleece550d2010-07-28 16:41:06 -04003893 if (idx != 0)
3894 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003895
John W. Linvilleece550d2010-07-28 16:41:06 -04003896 survey->channel = conf->channel;
3897 survey->filled = SURVEY_INFO_NOISE_DBM;
3898 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003899
John W. Linvilleece550d2010-07-28 16:41:06 -04003900 return 0;
3901}
3902
Arik Nemtsov409622e2011-02-23 00:22:29 +02003903static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003904 struct ieee80211_sta *sta,
3905 u8 *hlid)
3906{
3907 struct wl1271_station *wl_sta;
3908 int id;
3909
3910 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3911 if (id >= AP_MAX_STATIONS) {
3912 wl1271_warning("could not allocate HLID - too much stations");
3913 return -EBUSY;
3914 }
3915
3916 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsov04216da2011-08-14 13:17:38 +03003917 set_bit(id, wl->ap_hlid_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003918 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3919 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003920 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03003921 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003922 return 0;
3923}
3924
Arik Nemtsovf1acea92011-08-25 12:43:17 +03003925void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003926{
3927 int id = hlid - WL1271_AP_STA_HLID_START;
3928
Arik Nemtsovf1acea92011-08-25 12:43:17 +03003929 if (hlid < WL1271_AP_STA_HLID_START)
3930 return;
3931
3932 if (!test_bit(id, wl->ap_hlid_map))
Arik Nemtsov409622e2011-02-23 00:22:29 +02003933 return;
3934
Arik Nemtsov04216da2011-08-14 13:17:38 +03003935 clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003936 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003937 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003938 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003939 __clear_bit(hlid, &wl->ap_ps_map);
3940 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +03003941 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003942}
3943
3944static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3945 struct ieee80211_vif *vif,
3946 struct ieee80211_sta *sta)
3947{
3948 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003949 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003950 int ret = 0;
3951 u8 hlid;
3952
3953 mutex_lock(&wl->mutex);
3954
3955 if (unlikely(wl->state == WL1271_STATE_OFF))
3956 goto out;
3957
Eliad Peller536129c2011-10-05 11:55:45 +02003958 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003959 goto out;
3960
3961 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3962
Arik Nemtsov409622e2011-02-23 00:22:29 +02003963 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003964 if (ret < 0)
3965 goto out;
3966
Ido Yariva6208652011-03-01 15:14:41 +02003967 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003968 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003969 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003970
Eliad Pellerc690ec82011-08-14 13:17:07 +03003971 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003972 if (ret < 0)
3973 goto out_sleep;
3974
Eliad Pellerb67476e2011-08-14 13:17:23 +03003975 ret = wl12xx_cmd_set_peer_state(wl, hlid);
3976 if (ret < 0)
3977 goto out_sleep;
3978
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003979 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
3980 if (ret < 0)
3981 goto out_sleep;
3982
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003983out_sleep:
3984 wl1271_ps_elp_sleep(wl);
3985
Arik Nemtsov409622e2011-02-23 00:22:29 +02003986out_free_sta:
3987 if (ret < 0)
3988 wl1271_free_sta(wl, hlid);
3989
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003990out:
3991 mutex_unlock(&wl->mutex);
3992 return ret;
3993}
3994
3995static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3996 struct ieee80211_vif *vif,
3997 struct ieee80211_sta *sta)
3998{
3999 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004000 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004001 struct wl1271_station *wl_sta;
4002 int ret = 0, id;
4003
4004 mutex_lock(&wl->mutex);
4005
4006 if (unlikely(wl->state == WL1271_STATE_OFF))
4007 goto out;
4008
Eliad Peller536129c2011-10-05 11:55:45 +02004009 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004010 goto out;
4011
4012 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4013
4014 wl_sta = (struct wl1271_station *)sta->drv_priv;
4015 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
4016 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
4017 goto out;
4018
Ido Yariva6208652011-03-01 15:14:41 +02004019 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004020 if (ret < 0)
4021 goto out;
4022
Eliad Pellerc690ec82011-08-14 13:17:07 +03004023 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004024 if (ret < 0)
4025 goto out_sleep;
4026
Arik Nemtsov409622e2011-02-23 00:22:29 +02004027 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004028
4029out_sleep:
4030 wl1271_ps_elp_sleep(wl);
4031
4032out:
4033 mutex_unlock(&wl->mutex);
4034 return ret;
4035}
4036
Luciano Coelho4623ec72011-03-21 19:26:41 +02004037static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4038 struct ieee80211_vif *vif,
4039 enum ieee80211_ampdu_mlme_action action,
4040 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4041 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004042{
4043 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004044 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004045 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004046 u8 hlid, *ba_bitmap;
4047
4048 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4049 tid);
4050
4051 /* sanity check - the fields in FW are only 8bits wide */
4052 if (WARN_ON(tid > 0xFF))
4053 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004054
4055 mutex_lock(&wl->mutex);
4056
4057 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4058 ret = -EAGAIN;
4059 goto out;
4060 }
4061
Eliad Peller536129c2011-10-05 11:55:45 +02004062 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004063 hlid = wl->sta_hlid;
4064 ba_bitmap = &wl->ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004065 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004066 struct wl1271_station *wl_sta;
4067
4068 wl_sta = (struct wl1271_station *)sta->drv_priv;
4069 hlid = wl_sta->hlid;
4070 ba_bitmap = &wl->links[hlid].ba_bitmap;
4071 } else {
4072 ret = -EINVAL;
4073 goto out;
4074 }
4075
Ido Yariva6208652011-03-01 15:14:41 +02004076 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004077 if (ret < 0)
4078 goto out;
4079
Shahar Levi70559a02011-05-22 16:10:22 +03004080 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4081 tid, action);
4082
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004083 switch (action) {
4084 case IEEE80211_AMPDU_RX_START:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004085 if (!wl->ba_support || !wl->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004086 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004087 break;
4088 }
4089
4090 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4091 ret = -EBUSY;
4092 wl1271_error("exceeded max RX BA sessions");
4093 break;
4094 }
4095
4096 if (*ba_bitmap & BIT(tid)) {
4097 ret = -EINVAL;
4098 wl1271_error("cannot enable RX BA session on active "
4099 "tid: %d", tid);
4100 break;
4101 }
4102
4103 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4104 hlid);
4105 if (!ret) {
4106 *ba_bitmap |= BIT(tid);
4107 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004108 }
4109 break;
4110
4111 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004112 if (!(*ba_bitmap & BIT(tid))) {
4113 ret = -EINVAL;
4114 wl1271_error("no active RX BA session on tid: %d",
4115 tid);
4116 break;
4117 }
4118
4119 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4120 hlid);
4121 if (!ret) {
4122 *ba_bitmap &= ~BIT(tid);
4123 wl->ba_rx_session_count--;
4124 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004125 break;
4126
4127 /*
4128 * The BA initiator session management in FW independently.
4129 * Falling break here on purpose for all TX APDU commands.
4130 */
4131 case IEEE80211_AMPDU_TX_START:
4132 case IEEE80211_AMPDU_TX_STOP:
4133 case IEEE80211_AMPDU_TX_OPERATIONAL:
4134 ret = -EINVAL;
4135 break;
4136
4137 default:
4138 wl1271_error("Incorrect ampdu action id=%x\n", action);
4139 ret = -EINVAL;
4140 }
4141
4142 wl1271_ps_elp_sleep(wl);
4143
4144out:
4145 mutex_unlock(&wl->mutex);
4146
4147 return ret;
4148}
4149
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004150static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4151 struct ieee80211_vif *vif,
4152 const struct cfg80211_bitrate_mask *mask)
4153{
4154 struct wl1271 *wl = hw->priv;
4155 int i;
4156
4157 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4158 mask->control[NL80211_BAND_2GHZ].legacy,
4159 mask->control[NL80211_BAND_5GHZ].legacy);
4160
4161 mutex_lock(&wl->mutex);
4162
4163 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
4164 wl->bitrate_masks[i] =
4165 wl1271_tx_enabled_rates_get(wl,
4166 mask->control[i].legacy,
4167 i);
4168 mutex_unlock(&wl->mutex);
4169
4170 return 0;
4171}
4172
Shahar Levi6d158ff2011-09-08 13:01:33 +03004173static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4174 struct ieee80211_channel_switch *ch_switch)
4175{
4176 struct wl1271 *wl = hw->priv;
4177 int ret;
4178
4179 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4180
4181 mutex_lock(&wl->mutex);
4182
4183 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4184 mutex_unlock(&wl->mutex);
4185 ieee80211_chswitch_done(wl->vif, false);
4186 return;
4187 }
4188
4189 ret = wl1271_ps_elp_wakeup(wl);
4190 if (ret < 0)
4191 goto out;
4192
4193 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
4194
4195 if (!ret)
4196 set_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags);
4197
4198 wl1271_ps_elp_sleep(wl);
4199
4200out:
4201 mutex_unlock(&wl->mutex);
4202}
4203
Arik Nemtsov33437892011-04-26 23:35:39 +03004204static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4205{
4206 struct wl1271 *wl = hw->priv;
4207 bool ret = false;
4208
4209 mutex_lock(&wl->mutex);
4210
4211 if (unlikely(wl->state == WL1271_STATE_OFF))
4212 goto out;
4213
4214 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004215 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004216out:
4217 mutex_unlock(&wl->mutex);
4218
4219 return ret;
4220}
4221
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004222/* can't be const, mac80211 writes to this */
4223static struct ieee80211_rate wl1271_rates[] = {
4224 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004225 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4226 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004227 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004228 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4229 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004230 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4231 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004232 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4233 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004234 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4235 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004236 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4237 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004238 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4239 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004240 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4241 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004242 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004243 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4244 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004245 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004246 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4247 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004248 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004249 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4250 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004251 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004252 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4253 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004254 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004255 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4256 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004257 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004258 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4259 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004260 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004261 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4262 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004263};
4264
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004265/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004266static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004267 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004268 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004269 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4270 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4271 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004272 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004273 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4274 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4275 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004276 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004277 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4278 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4279 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004280 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004281};
4282
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004283/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004284static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004285 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004286 7, /* CONF_HW_RXTX_RATE_MCS7 */
4287 6, /* CONF_HW_RXTX_RATE_MCS6 */
4288 5, /* CONF_HW_RXTX_RATE_MCS5 */
4289 4, /* CONF_HW_RXTX_RATE_MCS4 */
4290 3, /* CONF_HW_RXTX_RATE_MCS3 */
4291 2, /* CONF_HW_RXTX_RATE_MCS2 */
4292 1, /* CONF_HW_RXTX_RATE_MCS1 */
4293 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004294
4295 11, /* CONF_HW_RXTX_RATE_54 */
4296 10, /* CONF_HW_RXTX_RATE_48 */
4297 9, /* CONF_HW_RXTX_RATE_36 */
4298 8, /* CONF_HW_RXTX_RATE_24 */
4299
4300 /* TI-specific rate */
4301 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4302
4303 7, /* CONF_HW_RXTX_RATE_18 */
4304 6, /* CONF_HW_RXTX_RATE_12 */
4305 3, /* CONF_HW_RXTX_RATE_11 */
4306 5, /* CONF_HW_RXTX_RATE_9 */
4307 4, /* CONF_HW_RXTX_RATE_6 */
4308 2, /* CONF_HW_RXTX_RATE_5_5 */
4309 1, /* CONF_HW_RXTX_RATE_2 */
4310 0 /* CONF_HW_RXTX_RATE_1 */
4311};
4312
Shahar Levie8b03a22010-10-13 16:09:39 +02004313/* 11n STA capabilities */
4314#define HW_RX_HIGHEST_RATE 72
4315
Shahar Levi00d20102010-11-08 11:20:10 +00004316#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004317 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4318 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004319 .ht_supported = true, \
4320 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4321 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4322 .mcs = { \
4323 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4324 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4325 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4326 }, \
4327}
4328
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004329/* can't be const, mac80211 writes to this */
4330static struct ieee80211_supported_band wl1271_band_2ghz = {
4331 .channels = wl1271_channels,
4332 .n_channels = ARRAY_SIZE(wl1271_channels),
4333 .bitrates = wl1271_rates,
4334 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004335 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004336};
4337
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004338/* 5 GHz data rates for WL1273 */
4339static struct ieee80211_rate wl1271_rates_5ghz[] = {
4340 { .bitrate = 60,
4341 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4342 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4343 { .bitrate = 90,
4344 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4345 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4346 { .bitrate = 120,
4347 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4348 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4349 { .bitrate = 180,
4350 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4351 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4352 { .bitrate = 240,
4353 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4354 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4355 { .bitrate = 360,
4356 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4357 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4358 { .bitrate = 480,
4359 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4360 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4361 { .bitrate = 540,
4362 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4363 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4364};
4365
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004366/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004367static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004368 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4369 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4370 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4371 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4372 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4373 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4374 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4375 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4376 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4377 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4378 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4379 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4380 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4381 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4382 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4383 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4384 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4385 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4386 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4387 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4388 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4389 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4390 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4391 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4392 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4393 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4394 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4395 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4396 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4397 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4398 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4399 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4400 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4401 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004402};
4403
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004404/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004405static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004406 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004407 7, /* CONF_HW_RXTX_RATE_MCS7 */
4408 6, /* CONF_HW_RXTX_RATE_MCS6 */
4409 5, /* CONF_HW_RXTX_RATE_MCS5 */
4410 4, /* CONF_HW_RXTX_RATE_MCS4 */
4411 3, /* CONF_HW_RXTX_RATE_MCS3 */
4412 2, /* CONF_HW_RXTX_RATE_MCS2 */
4413 1, /* CONF_HW_RXTX_RATE_MCS1 */
4414 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004415
4416 7, /* CONF_HW_RXTX_RATE_54 */
4417 6, /* CONF_HW_RXTX_RATE_48 */
4418 5, /* CONF_HW_RXTX_RATE_36 */
4419 4, /* CONF_HW_RXTX_RATE_24 */
4420
4421 /* TI-specific rate */
4422 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4423
4424 3, /* CONF_HW_RXTX_RATE_18 */
4425 2, /* CONF_HW_RXTX_RATE_12 */
4426 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4427 1, /* CONF_HW_RXTX_RATE_9 */
4428 0, /* CONF_HW_RXTX_RATE_6 */
4429 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4430 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4431 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4432};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004433
4434static struct ieee80211_supported_band wl1271_band_5ghz = {
4435 .channels = wl1271_channels_5ghz,
4436 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4437 .bitrates = wl1271_rates_5ghz,
4438 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004439 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004440};
4441
Tobias Klausera0ea9492010-05-20 10:38:11 +02004442static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004443 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4444 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4445};
4446
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004447static const struct ieee80211_ops wl1271_ops = {
4448 .start = wl1271_op_start,
4449 .stop = wl1271_op_stop,
4450 .add_interface = wl1271_op_add_interface,
4451 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004452#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004453 .suspend = wl1271_op_suspend,
4454 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004455#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004456 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004457 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004458 .configure_filter = wl1271_op_configure_filter,
4459 .tx = wl1271_op_tx,
4460 .set_key = wl1271_op_set_key,
4461 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004462 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004463 .sched_scan_start = wl1271_op_sched_scan_start,
4464 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004465 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004466 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004467 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004468 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004469 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004470 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004471 .sta_add = wl1271_op_sta_add,
4472 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004473 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004474 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004475 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004476 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004477 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004478};
4479
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004480
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004481u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004482{
4483 u8 idx;
4484
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004485 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004486
4487 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4488 wl1271_error("Illegal RX rate from HW: %d", rate);
4489 return 0;
4490 }
4491
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004492 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004493 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4494 wl1271_error("Unsupported RX rate from HW: %d", rate);
4495 return 0;
4496 }
4497
4498 return idx;
4499}
4500
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004501static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4502 struct device_attribute *attr,
4503 char *buf)
4504{
4505 struct wl1271 *wl = dev_get_drvdata(dev);
4506 ssize_t len;
4507
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004508 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004509
4510 mutex_lock(&wl->mutex);
4511 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4512 wl->sg_enabled);
4513 mutex_unlock(&wl->mutex);
4514
4515 return len;
4516
4517}
4518
4519static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4520 struct device_attribute *attr,
4521 const char *buf, size_t count)
4522{
4523 struct wl1271 *wl = dev_get_drvdata(dev);
4524 unsigned long res;
4525 int ret;
4526
Luciano Coelho6277ed62011-04-01 17:49:54 +03004527 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004528 if (ret < 0) {
4529 wl1271_warning("incorrect value written to bt_coex_mode");
4530 return count;
4531 }
4532
4533 mutex_lock(&wl->mutex);
4534
4535 res = !!res;
4536
4537 if (res == wl->sg_enabled)
4538 goto out;
4539
4540 wl->sg_enabled = res;
4541
4542 if (wl->state == WL1271_STATE_OFF)
4543 goto out;
4544
Ido Yariva6208652011-03-01 15:14:41 +02004545 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004546 if (ret < 0)
4547 goto out;
4548
4549 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4550 wl1271_ps_elp_sleep(wl);
4551
4552 out:
4553 mutex_unlock(&wl->mutex);
4554 return count;
4555}
4556
4557static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4558 wl1271_sysfs_show_bt_coex_state,
4559 wl1271_sysfs_store_bt_coex_state);
4560
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004561static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4562 struct device_attribute *attr,
4563 char *buf)
4564{
4565 struct wl1271 *wl = dev_get_drvdata(dev);
4566 ssize_t len;
4567
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004568 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004569
4570 mutex_lock(&wl->mutex);
4571 if (wl->hw_pg_ver >= 0)
4572 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4573 else
4574 len = snprintf(buf, len, "n/a\n");
4575 mutex_unlock(&wl->mutex);
4576
4577 return len;
4578}
4579
Gery Kahn6f07b722011-07-18 14:21:49 +03004580static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004581 wl1271_sysfs_show_hw_pg_ver, NULL);
4582
Ido Yariv95dac04f2011-06-06 14:57:06 +03004583static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4584 struct bin_attribute *bin_attr,
4585 char *buffer, loff_t pos, size_t count)
4586{
4587 struct device *dev = container_of(kobj, struct device, kobj);
4588 struct wl1271 *wl = dev_get_drvdata(dev);
4589 ssize_t len;
4590 int ret;
4591
4592 ret = mutex_lock_interruptible(&wl->mutex);
4593 if (ret < 0)
4594 return -ERESTARTSYS;
4595
4596 /* Let only one thread read the log at a time, blocking others */
4597 while (wl->fwlog_size == 0) {
4598 DEFINE_WAIT(wait);
4599
4600 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4601 &wait,
4602 TASK_INTERRUPTIBLE);
4603
4604 if (wl->fwlog_size != 0) {
4605 finish_wait(&wl->fwlog_waitq, &wait);
4606 break;
4607 }
4608
4609 mutex_unlock(&wl->mutex);
4610
4611 schedule();
4612 finish_wait(&wl->fwlog_waitq, &wait);
4613
4614 if (signal_pending(current))
4615 return -ERESTARTSYS;
4616
4617 ret = mutex_lock_interruptible(&wl->mutex);
4618 if (ret < 0)
4619 return -ERESTARTSYS;
4620 }
4621
4622 /* Check if the fwlog is still valid */
4623 if (wl->fwlog_size < 0) {
4624 mutex_unlock(&wl->mutex);
4625 return 0;
4626 }
4627
4628 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4629 len = min(count, (size_t)wl->fwlog_size);
4630 wl->fwlog_size -= len;
4631 memcpy(buffer, wl->fwlog, len);
4632
4633 /* Make room for new messages */
4634 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4635
4636 mutex_unlock(&wl->mutex);
4637
4638 return len;
4639}
4640
4641static struct bin_attribute fwlog_attr = {
4642 .attr = {.name = "fwlog", .mode = S_IRUSR},
4643 .read = wl1271_sysfs_read_fwlog,
4644};
4645
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004646int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004647{
4648 int ret;
4649
4650 if (wl->mac80211_registered)
4651 return 0;
4652
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004653 ret = wl1271_fetch_nvs(wl);
4654 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004655 /* NOTE: The wl->nvs->nvs element must be first, in
4656 * order to simplify the casting, we assume it is at
4657 * the beginning of the wl->nvs structure.
4658 */
4659 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004660
4661 wl->mac_addr[0] = nvs_ptr[11];
4662 wl->mac_addr[1] = nvs_ptr[10];
4663 wl->mac_addr[2] = nvs_ptr[6];
4664 wl->mac_addr[3] = nvs_ptr[5];
4665 wl->mac_addr[4] = nvs_ptr[4];
4666 wl->mac_addr[5] = nvs_ptr[3];
4667 }
4668
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004669 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4670
4671 ret = ieee80211_register_hw(wl->hw);
4672 if (ret < 0) {
4673 wl1271_error("unable to register mac80211 hw: %d", ret);
4674 return ret;
4675 }
4676
4677 wl->mac80211_registered = true;
4678
Eliad Pellerd60080a2010-11-24 12:53:16 +02004679 wl1271_debugfs_init(wl);
4680
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004681 register_netdevice_notifier(&wl1271_dev_notifier);
4682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004683 wl1271_notice("loaded");
4684
4685 return 0;
4686}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004687EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004688
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004689void wl1271_unregister_hw(struct wl1271 *wl)
4690{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004691 if (wl->state == WL1271_STATE_PLT)
4692 __wl1271_plt_stop(wl);
4693
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004694 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004695 ieee80211_unregister_hw(wl->hw);
4696 wl->mac80211_registered = false;
4697
4698}
4699EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4700
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004701int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004702{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004703 static const u32 cipher_suites[] = {
4704 WLAN_CIPHER_SUITE_WEP40,
4705 WLAN_CIPHER_SUITE_WEP104,
4706 WLAN_CIPHER_SUITE_TKIP,
4707 WLAN_CIPHER_SUITE_CCMP,
4708 WL1271_CIPHER_SUITE_GEM,
4709 };
4710
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004711 /* The tx descriptor buffer and the TKIP space. */
4712 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4713 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004714
4715 /* unit us */
4716 /* FIXME: find a proper value */
4717 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004718 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004719
4720 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004721 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004722 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004723 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004724 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004725 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004726 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004727 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004728 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004729 IEEE80211_HW_AP_LINK_PS |
4730 IEEE80211_HW_AMPDU_AGGREGATION |
4731 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004732
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004733 wl->hw->wiphy->cipher_suites = cipher_suites;
4734 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4735
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004736 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004737 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4738 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004739 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004740 wl->hw->wiphy->max_sched_scan_ssids = 16;
4741 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004742 /*
4743 * Maximum length of elements in scanning probe request templates
4744 * should be the maximum length possible for a template, without
4745 * the IEEE80211 header of the template
4746 */
Eliad Peller154037d2011-08-14 13:17:12 +03004747 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004748 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004749
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004750 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4751 sizeof(struct ieee80211_header);
4752
Eliad Peller1ec23f72011-08-25 14:26:54 +03004753 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4754
Luciano Coelho4a31c112011-03-21 23:16:14 +02004755 /* make sure all our channels fit in the scanned_ch bitmask */
4756 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4757 ARRAY_SIZE(wl1271_channels_5ghz) >
4758 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004759 /*
4760 * We keep local copies of the band structs because we need to
4761 * modify them on a per-device basis.
4762 */
4763 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4764 sizeof(wl1271_band_2ghz));
4765 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4766 sizeof(wl1271_band_5ghz));
4767
4768 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4769 &wl->bands[IEEE80211_BAND_2GHZ];
4770 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4771 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004772
Kalle Valo12bd8942010-03-18 12:26:33 +02004773 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004774 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004775
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004776 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4777
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004778 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004779
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004780 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004781 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004782
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004783 wl->hw->max_rx_aggregation_subframes = 8;
4784
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004785 return 0;
4786}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004787EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004788
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004789#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004790
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004791struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004792{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004793 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004794 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004795 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004796 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004797 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004798
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004799 BUILD_BUG_ON(AP_MAX_LINKS > WL12XX_MAX_LINKS);
4800
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004801 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4802 if (!hw) {
4803 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004804 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004805 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004806 }
4807
Julia Lawall929ebd32010-05-15 23:16:39 +02004808 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004809 if (!plat_dev) {
4810 wl1271_error("could not allocate platform_device");
4811 ret = -ENOMEM;
4812 goto err_plat_alloc;
4813 }
4814
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004815 wl = hw->priv;
4816 memset(wl, 0, sizeof(*wl));
4817
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004818 INIT_LIST_HEAD(&wl->list);
4819
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004820 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004821 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004822
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004823 for (i = 0; i < NUM_TX_QUEUES; i++)
4824 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004825
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004826 for (i = 0; i < NUM_TX_QUEUES; i++)
4827 for (j = 0; j < AP_MAX_LINKS; j++)
4828 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4829
Ido Yariva6208652011-03-01 15:14:41 +02004830 skb_queue_head_init(&wl->deferred_rx_queue);
4831 skb_queue_head_init(&wl->deferred_tx_queue);
4832
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004833 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004834 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004835 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004836 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4837 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4838 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004839 INIT_WORK(&wl->rx_streaming_enable_work,
4840 wl1271_rx_streaming_enable_work);
4841 INIT_WORK(&wl->rx_streaming_disable_work,
4842 wl1271_rx_streaming_disable_work);
4843
Eliad Peller92ef8962011-06-07 12:50:46 +03004844 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4845 if (!wl->freezable_wq) {
4846 ret = -ENOMEM;
4847 goto err_hw;
4848 }
4849
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004850 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004851 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004852 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004853 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004854 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004855 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004856 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004857 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004858 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004859 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004860 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004861 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004862 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004863 wl->ap_ps_map = 0;
4864 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004865 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004866 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004867 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004868 wl->tx_security_seq = 0;
4869 wl->tx_security_last_seq_lsb = 0;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03004870 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Peller7f0979882011-08-14 13:17:06 +03004871 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004872 wl->system_hlid = WL12XX_SYSTEM_HLID;
Eliad Peller7f0979882011-08-14 13:17:06 +03004873 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004874 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4875 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsov712e9bf2011-08-14 13:17:20 +03004876 wl->session_counter = 0;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03004877 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
4878 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsovda032092011-08-25 12:43:15 +03004879 wl->active_sta_count = 0;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004880 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4881 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004882 wl->fwlog_size = 0;
4883 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004884
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004885 /* The system link is always allocated */
4886 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4887
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004888 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004889 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004890 wl->tx_frames[i] = NULL;
4891
4892 spin_lock_init(&wl->wl_lock);
4893
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004894 wl->state = WL1271_STATE_OFF;
4895 mutex_init(&wl->mutex);
4896
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004897 /* Apply default driver configuration. */
4898 wl1271_conf_init(wl);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004899 wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
4900 wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004901
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004902 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4903 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4904 if (!wl->aggr_buf) {
4905 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004906 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004907 }
4908
Ido Yariv990f5de2011-03-31 10:06:59 +02004909 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4910 if (!wl->dummy_packet) {
4911 ret = -ENOMEM;
4912 goto err_aggr;
4913 }
4914
Ido Yariv95dac04f2011-06-06 14:57:06 +03004915 /* Allocate one page for the FW log */
4916 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4917 if (!wl->fwlog) {
4918 ret = -ENOMEM;
4919 goto err_dummy_packet;
4920 }
4921
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004922 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004923 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004924 if (ret) {
4925 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004926 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004927 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004928 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004929
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004930 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004931 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004932 if (ret < 0) {
4933 wl1271_error("failed to create sysfs file bt_coex_state");
4934 goto err_platform;
4935 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004936
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004937 /* Create sysfs file to get HW PG version */
4938 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4939 if (ret < 0) {
4940 wl1271_error("failed to create sysfs file hw_pg_ver");
4941 goto err_bt_coex_state;
4942 }
4943
Ido Yariv95dac04f2011-06-06 14:57:06 +03004944 /* Create sysfs file for the FW log */
4945 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4946 if (ret < 0) {
4947 wl1271_error("failed to create sysfs file fwlog");
4948 goto err_hw_pg_ver;
4949 }
4950
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004951 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004952
Ido Yariv95dac04f2011-06-06 14:57:06 +03004953err_hw_pg_ver:
4954 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4955
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004956err_bt_coex_state:
4957 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4958
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004959err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004960 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004961
Ido Yariv95dac04f2011-06-06 14:57:06 +03004962err_fwlog:
4963 free_page((unsigned long)wl->fwlog);
4964
Ido Yariv990f5de2011-03-31 10:06:59 +02004965err_dummy_packet:
4966 dev_kfree_skb(wl->dummy_packet);
4967
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004968err_aggr:
4969 free_pages((unsigned long)wl->aggr_buf, order);
4970
Eliad Peller92ef8962011-06-07 12:50:46 +03004971err_wq:
4972 destroy_workqueue(wl->freezable_wq);
4973
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004974err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004975 wl1271_debugfs_exit(wl);
4976 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004977
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004978err_plat_alloc:
4979 ieee80211_free_hw(hw);
4980
4981err_hw_alloc:
4982
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004983 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004984}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004985EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004986
4987int wl1271_free_hw(struct wl1271 *wl)
4988{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004989 /* Unblock any fwlog readers */
4990 mutex_lock(&wl->mutex);
4991 wl->fwlog_size = -1;
4992 wake_up_interruptible_all(&wl->fwlog_waitq);
4993 mutex_unlock(&wl->mutex);
4994
4995 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004996
4997 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4998
4999 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005000 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005001 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005002 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005003 free_pages((unsigned long)wl->aggr_buf,
5004 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005005 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005006
5007 wl1271_debugfs_exit(wl);
5008
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005009 vfree(wl->fw);
5010 wl->fw = NULL;
5011 kfree(wl->nvs);
5012 wl->nvs = NULL;
5013
5014 kfree(wl->fw_status);
5015 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005016 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005017
5018 ieee80211_free_hw(wl->hw);
5019
5020 return 0;
5021}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005022EXPORT_SYMBOL_GPL(wl1271_free_hw);
5023
Guy Eilam491bbd62011-01-12 10:33:29 +01005024u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005025EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005026module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005027MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5028
Ido Yariv95dac04f2011-06-06 14:57:06 +03005029module_param_named(fwlog, fwlog_param, charp, 0);
5030MODULE_PARM_DESC(keymap,
5031 "FW logger options: continuous, ondemand, dbgpins or disable");
5032
Eliad Peller2a5bff02011-08-25 18:10:59 +03005033module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5034MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5035
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005036MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005037MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005038MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");