blob: 2eb1471ac4ec0e5cf1e4573318af7eebe36d0d98 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000038#include "reg.h"
39#include "io.h"
40#include "event.h"
41#include "tx.h"
42#include "rx.h"
43#include "ps.h"
44#include "init.h"
45#include "debugfs.h"
46#include "cmd.h"
47#include "boot.h"
48#include "testmode.h"
49#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030050
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020051#define WL1271_BOOT_RETRIES 3
52
Juuso Oikarinen8a080482009-10-13 12:47:44 +030053static struct conf_drv_settings default_conf = {
54 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030055 .params = {
56 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
57 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
58 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
61 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
62 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
64 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
65 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
66 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
68 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
69 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
70 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
71 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
73 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
74 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
75 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
76 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
77 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
78 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
79 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
82 /* active scan params */
83 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
84 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
85 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
86 /* passive scan params */
87 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
88 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
90 /* passive scan in dual antenna params */
91 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
92 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
93 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
94 /* general params */
95 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
96 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
97 [CONF_SG_BEACON_MISS_PERCENT] = 60,
98 [CONF_SG_DHCP_TIME] = 5000,
99 [CONF_SG_RXT] = 1200,
100 [CONF_SG_TXT] = 1000,
101 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
102 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
103 [CONF_SG_HV3_MAX_SERVED] = 6,
104 [CONF_SG_PS_POLL_TIMEOUT] = 10,
105 [CONF_SG_UPSD_TIMEOUT] = 10,
106 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
107 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
108 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
109 /* AP params */
110 [CONF_AP_BEACON_MISS_TX] = 3,
111 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
112 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
113 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
114 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
115 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300116 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200117 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300118 },
119 .rx = {
120 .rx_msdu_life_time = 512000,
121 .packet_detection_threshold = 0,
122 .ps_poll_timeout = 15,
123 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300124 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200125 .rx_cca_threshold = 0,
126 .irq_blk_threshold = 0xFFFF,
127 .irq_pkt_threshold = 0,
128 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300129 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
130 },
131 .tx = {
132 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200133 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300134 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .short_retry_limit = 10,
136 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200137 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300138 },
139 .ac_conf_count = 4,
140 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_BE,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = 3,
146 .tx_op_limit = 0,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_BK,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = 7,
153 .tx_op_limit = 0,
154 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200155 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300156 .ac = CONF_TX_AC_VI,
157 .cw_min = 15,
158 .cw_max = 63,
159 .aifsn = CONF_TX_AIFS_PIFS,
160 .tx_op_limit = 3008,
161 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200162 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300163 .ac = CONF_TX_AC_VO,
164 .cw_min = 15,
165 .cw_max = 63,
166 .aifsn = CONF_TX_AIFS_PIFS,
167 .tx_op_limit = 1504,
168 },
169 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300170 .max_tx_retries = 100,
171 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200172 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300173 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 [CONF_TX_AC_BE] = {
175 .queue_id = CONF_TX_AC_BE,
176 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .tsid = CONF_TX_AC_BE,
178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200182 [CONF_TX_AC_BK] = {
183 .queue_id = CONF_TX_AC_BK,
184 .channel_type = CONF_CHANNEL_TYPE_EDCF,
185 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_VI] = {
191 .queue_id = CONF_TX_AC_VI,
192 .channel_type = CONF_CHANNEL_TYPE_EDCF,
193 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300194 .ps_scheme = CONF_PS_SCHEME_LEGACY,
195 .ack_policy = CONF_ACK_POLICY_LEGACY,
196 .apsd_conf = {0, 0},
197 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200198 [CONF_TX_AC_VO] = {
199 .queue_id = CONF_TX_AC_VO,
200 .channel_type = CONF_CHANNEL_TYPE_EDCF,
201 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300202 .ps_scheme = CONF_PS_SCHEME_LEGACY,
203 .ack_policy = CONF_ACK_POLICY_LEGACY,
204 .apsd_conf = {0, 0},
205 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300206 },
207 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200208 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300209 .tx_compl_threshold = 4,
210 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
211 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200212 .tmpl_short_retry_limit = 10,
213 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300214 },
215 .conn = {
216 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300217 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300219 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_ie = {
221 [0] = {
222 .ie = WLAN_EID_CHANNEL_SWITCH,
223 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300224 },
225 [1] = {
226 .ie = WLAN_EID_HT_INFORMATION,
227 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200230 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 .bss_lose_timeout = 100,
232 .beacon_rx_timeout = 10000,
233 .broadcast_timeout = 20000,
234 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300235 .ps_poll_threshold = 10,
236 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300237 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200238 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300239 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300240 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200241 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300242 .keep_alive_interval = 55000,
243 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300244 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200245 .itrim = {
246 .enable = false,
247 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200248 },
249 .pm_config = {
250 .host_clk_settling_time = 5000,
251 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300252 },
253 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 .trigger_pacing = 1,
255 .avg_weight_rssi_beacon = 20,
256 .avg_weight_rssi_data = 10,
257 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100258 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200259 },
260 .scan = {
261 .min_dwell_time_active = 7500,
262 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100263 .min_dwell_time_passive = 100000,
264 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200265 .num_probe_reqs = 2,
266 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300267 .sched_scan = {
268 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300269 .min_dwell_time_active = 30,
270 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300271 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300272 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .num_probe_reqs = 2,
274 .rssi_threshold = -90,
275 .snr_threshold = 0,
276 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200277 .rf = {
278 .tx_per_channel_power_compensation_2 = {
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 },
281 .tx_per_channel_power_compensation_5 = {
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 },
286 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100287 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300288 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .tx_ba_win_size = 64,
290 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300291 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100292 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200293 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200294 .num_stations = 1,
295 .ssid_profiles = 1,
296 .rx_block_num = 70,
297 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300298 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200299 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200300 .min_req_rx_blocks = 22,
301 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200302 },
303 .mem_wl128x = {
304 .num_stations = 1,
305 .ssid_profiles = 1,
306 .rx_block_num = 40,
307 .tx_min_block_num = 40,
308 .dynamic_memory = 1,
309 .min_req_tx_blocks = 45,
310 .min_req_rx_blocks = 22,
311 .tx_min = 27,
312 },
Shahar Leviff868432011-04-11 15:41:46 +0300313 .fm_coex = {
314 .enable = true,
315 .swallow_period = 5,
316 .n_divider_fref_set_1 = 0xff, /* default */
317 .n_divider_fref_set_2 = 12,
318 .m_divider_fref_set_1 = 148,
319 .m_divider_fref_set_2 = 0xffff, /* default */
320 .coex_pll_stabilization_time = 0xffffffff, /* default */
321 .ldo_stabilization_time = 0xffff, /* default */
322 .fm_disturbed_band_margin = 0xff, /* default */
323 .swallow_clk_diff = 0xff, /* default */
324 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300325 .rx_streaming = {
326 .duration = 150,
327 .queues = 0x1,
328 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300329 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300330 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300331 .fwlog = {
332 .mode = WL12XX_FWLOG_ON_DEMAND,
333 .mem_blocks = 2,
334 .severity = 0,
335 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
336 .output = WL12XX_FWLOG_OUTPUT_HOST,
337 .threshold = 0,
338 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300339 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300340 .rate = {
341 .rate_retry_score = 32000,
342 .per_add = 8192,
343 .per_th1 = 2048,
344 .per_th2 = 4096,
345 .max_per = 8100,
346 .inverse_curiosity_factor = 5,
347 .tx_fail_low_th = 4,
348 .tx_fail_high_th = 10,
349 .per_alpha_shift = 4,
350 .per_add_shift = 13,
351 .per_beta1_shift = 10,
352 .per_beta2_shift = 8,
353 .rate_check_up = 2,
354 .rate_check_down = 12,
355 .rate_retry_policy = {
356 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00,
359 },
360 },
Eliad Peller94877752011-08-28 15:11:56 +0300361 .hangover = {
362 .recover_time = 0,
363 .hangover_period = 20,
364 .dynamic_mode = 1,
365 .early_termination_mode = 1,
366 .max_period = 20,
367 .min_period = 1,
368 .increase_delta = 1,
369 .decrease_delta = 2,
370 .quiet_time = 4,
371 .increase_time = 1,
372 .window_size = 16,
373 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300374};
375
Ido Yariv95dac04f2011-06-06 14:57:06 +0300376static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300377static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300379static void __wl1271_op_remove_interface(struct wl1271 *wl,
380 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200381static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200382
383
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200384static void wl1271_device_release(struct device *dev)
385{
386
387}
388
389static struct platform_device wl1271_device = {
390 .name = "wl1271",
391 .id = -1,
392
393 /* device model insists to have a release function */
394 .dev = {
395 .release = wl1271_device_release,
396 },
397};
398
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200399static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300400static LIST_HEAD(wl_list);
401
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300402static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
403{
404 int ret;
405 if (operstate != IF_OPER_UP)
406 return 0;
407
408 if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
409 return 0;
410
Eliad Pellerb67476e2011-08-14 13:17:23 +0300411 ret = wl12xx_cmd_set_peer_state(wl, wl->sta_hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300412 if (ret < 0)
413 return ret;
414
Eliad Peller251c1772011-08-14 13:17:17 +0300415 wl12xx_croc(wl, wl->role_id);
416
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300417 wl1271_info("Association completed.");
418 return 0;
419}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300420static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
421 void *arg)
422{
423 struct net_device *dev = arg;
424 struct wireless_dev *wdev;
425 struct wiphy *wiphy;
426 struct ieee80211_hw *hw;
427 struct wl1271 *wl;
428 struct wl1271 *wl_temp;
429 int ret = 0;
430
431 /* Check that this notification is for us. */
432 if (what != NETDEV_CHANGE)
433 return NOTIFY_DONE;
434
435 wdev = dev->ieee80211_ptr;
436 if (wdev == NULL)
437 return NOTIFY_DONE;
438
439 wiphy = wdev->wiphy;
440 if (wiphy == NULL)
441 return NOTIFY_DONE;
442
443 hw = wiphy_priv(wiphy);
444 if (hw == NULL)
445 return NOTIFY_DONE;
446
447 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200448 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300449 list_for_each_entry(wl, &wl_list, list) {
450 if (wl == wl_temp)
451 break;
452 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200453 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300454 if (wl != wl_temp)
455 return NOTIFY_DONE;
456
457 mutex_lock(&wl->mutex);
458
459 if (wl->state == WL1271_STATE_OFF)
460 goto out;
461
462 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
463 goto out;
464
Ido Yariva6208652011-03-01 15:14:41 +0200465 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300466 if (ret < 0)
467 goto out;
468
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300469 wl1271_check_operstate(wl, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300470
471 wl1271_ps_elp_sleep(wl);
472
473out:
474 mutex_unlock(&wl->mutex);
475
476 return NOTIFY_OK;
477}
478
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100479static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200480 struct regulatory_request *request)
481{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100482 struct ieee80211_supported_band *band;
483 struct ieee80211_channel *ch;
484 int i;
485
486 band = wiphy->bands[IEEE80211_BAND_5GHZ];
487 for (i = 0; i < band->n_channels; i++) {
488 ch = &band->channels[i];
489 if (ch->flags & IEEE80211_CHAN_DISABLED)
490 continue;
491
492 if (ch->flags & IEEE80211_CHAN_RADAR)
493 ch->flags |= IEEE80211_CHAN_NO_IBSS |
494 IEEE80211_CHAN_PASSIVE_SCAN;
495
496 }
497
498 return 0;
499}
500
Eliad Peller77ddaa12011-05-15 11:10:29 +0300501static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
502{
503 int ret = 0;
504
505 /* we should hold wl->mutex */
506 ret = wl1271_acx_ps_rx_streaming(wl, enable);
507 if (ret < 0)
508 goto out;
509
510 if (enable)
511 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
512 else
513 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
514out:
515 return ret;
516}
517
518/*
519 * this function is being called when the rx_streaming interval
520 * has beed changed or rx_streaming should be disabled
521 */
522int wl1271_recalc_rx_streaming(struct wl1271 *wl)
523{
524 int ret = 0;
525 int period = wl->conf.rx_streaming.interval;
526
527 /* don't reconfigure if rx_streaming is disabled */
528 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
529 goto out;
530
531 /* reconfigure/disable according to new streaming_period */
532 if (period &&
533 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
534 (wl->conf.rx_streaming.always ||
535 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
536 ret = wl1271_set_rx_streaming(wl, true);
537 else {
538 ret = wl1271_set_rx_streaming(wl, false);
539 /* don't cancel_work_sync since we might deadlock */
540 del_timer_sync(&wl->rx_streaming_timer);
541 }
542out:
543 return ret;
544}
545
546static void wl1271_rx_streaming_enable_work(struct work_struct *work)
547{
548 int ret;
549 struct wl1271 *wl =
550 container_of(work, struct wl1271, rx_streaming_enable_work);
551
552 mutex_lock(&wl->mutex);
553
554 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
555 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
556 (!wl->conf.rx_streaming.always &&
557 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
558 goto out;
559
560 if (!wl->conf.rx_streaming.interval)
561 goto out;
562
563 ret = wl1271_ps_elp_wakeup(wl);
564 if (ret < 0)
565 goto out;
566
567 ret = wl1271_set_rx_streaming(wl, true);
568 if (ret < 0)
569 goto out_sleep;
570
571 /* stop it after some time of inactivity */
572 mod_timer(&wl->rx_streaming_timer,
573 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
574
575out_sleep:
576 wl1271_ps_elp_sleep(wl);
577out:
578 mutex_unlock(&wl->mutex);
579}
580
581static void wl1271_rx_streaming_disable_work(struct work_struct *work)
582{
583 int ret;
584 struct wl1271 *wl =
585 container_of(work, struct wl1271, rx_streaming_disable_work);
586
587 mutex_lock(&wl->mutex);
588
589 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
590 goto out;
591
592 ret = wl1271_ps_elp_wakeup(wl);
593 if (ret < 0)
594 goto out;
595
596 ret = wl1271_set_rx_streaming(wl, false);
597 if (ret)
598 goto out_sleep;
599
600out_sleep:
601 wl1271_ps_elp_sleep(wl);
602out:
603 mutex_unlock(&wl->mutex);
604}
605
606static void wl1271_rx_streaming_timer(unsigned long data)
607{
608 struct wl1271 *wl = (struct wl1271 *)data;
609 ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
610}
611
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300612static void wl1271_conf_init(struct wl1271 *wl)
613{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300614
615 /*
616 * This function applies the default configuration to the driver. This
617 * function is invoked upon driver load (spi probe.)
618 *
619 * The configuration is stored in a run-time structure in order to
620 * facilitate for run-time adjustment of any of the parameters. Making
621 * changes to the configuration structure will apply the new values on
622 * the next interface up (wl1271_op_start.)
623 */
624
625 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300626 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300627
Ido Yariv95dac04f2011-06-06 14:57:06 +0300628 /* Adjust settings according to optional module parameters */
629 if (fwlog_param) {
630 if (!strcmp(fwlog_param, "continuous")) {
631 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
632 } else if (!strcmp(fwlog_param, "ondemand")) {
633 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
634 } else if (!strcmp(fwlog_param, "dbgpins")) {
635 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
636 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
637 } else if (!strcmp(fwlog_param, "disable")) {
638 wl->conf.fwlog.mem_blocks = 0;
639 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
640 } else {
641 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
642 }
643 }
644}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300645
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300646static int wl1271_plt_init(struct wl1271 *wl)
647{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200648 struct conf_tx_ac_category *conf_ac;
649 struct conf_tx_tid *conf_tid;
650 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651
Shahar Levi49d750ca2011-03-06 16:32:09 +0200652 if (wl->chip.id == CHIP_ID_1283_PG20)
653 ret = wl128x_cmd_general_parms(wl);
654 else
655 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200656 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200657 return ret;
658
Shahar Levi49d750ca2011-03-06 16:32:09 +0200659 if (wl->chip.id == CHIP_ID_1283_PG20)
660 ret = wl128x_cmd_radio_parms(wl);
661 else
662 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200663 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200664 return ret;
665
Shahar Levi49d750ca2011-03-06 16:32:09 +0200666 if (wl->chip.id != CHIP_ID_1283_PG20) {
667 ret = wl1271_cmd_ext_radio_parms(wl);
668 if (ret < 0)
669 return ret;
670 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200671 if (ret < 0)
672 return ret;
673
Shahar Levi48a61472011-03-06 16:32:08 +0200674 /* Chip-specific initializations */
675 ret = wl1271_chip_specific_init(wl);
676 if (ret < 0)
677 return ret;
678
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200679 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200680 if (ret < 0)
681 return ret;
682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 ret = wl1271_acx_init_mem_config(wl);
684 if (ret < 0)
685 return ret;
686
Luciano Coelho12419cc2010-02-18 13:25:44 +0200687 /* PHY layer config */
688 ret = wl1271_init_phy_config(wl);
689 if (ret < 0)
690 goto out_free_memmap;
691
692 ret = wl1271_acx_dco_itrim_params(wl);
693 if (ret < 0)
694 goto out_free_memmap;
695
696 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200697 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200698 if (ret < 0)
699 goto out_free_memmap;
700
701 /* Bluetooth WLAN coexistence */
702 ret = wl1271_init_pta(wl);
703 if (ret < 0)
704 goto out_free_memmap;
705
Shahar Leviff868432011-04-11 15:41:46 +0300706 /* FM WLAN coexistence */
707 ret = wl1271_acx_fm_coex(wl);
708 if (ret < 0)
709 goto out_free_memmap;
710
Luciano Coelho12419cc2010-02-18 13:25:44 +0200711 /* Energy detection */
712 ret = wl1271_init_energy_detection(wl);
713 if (ret < 0)
714 goto out_free_memmap;
715
Eliad Peller7f0979882011-08-14 13:17:06 +0300716 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600717 if (ret < 0)
718 goto out_free_memmap;
719
Luciano Coelho12419cc2010-02-18 13:25:44 +0200720 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100721 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200722 if (ret < 0)
723 goto out_free_memmap;
724
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200725 /* Default TID/AC configuration */
726 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200727 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200728 conf_ac = &wl->conf.tx.ac_conf[i];
729 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
730 conf_ac->cw_max, conf_ac->aifsn,
731 conf_ac->tx_op_limit);
732 if (ret < 0)
733 goto out_free_memmap;
734
Luciano Coelho12419cc2010-02-18 13:25:44 +0200735 conf_tid = &wl->conf.tx.tid_conf[i];
736 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
737 conf_tid->channel_type,
738 conf_tid->tsid,
739 conf_tid->ps_scheme,
740 conf_tid->ack_policy,
741 conf_tid->apsd_conf[0],
742 conf_tid->apsd_conf[1]);
743 if (ret < 0)
744 goto out_free_memmap;
745 }
746
Luciano Coelho12419cc2010-02-18 13:25:44 +0200747 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200748 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300749 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200750 goto out_free_memmap;
751
752 /* Configure for CAM power saving (ie. always active) */
753 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
754 if (ret < 0)
755 goto out_free_memmap;
756
757 /* configure PM */
758 ret = wl1271_acx_pm_config(wl);
759 if (ret < 0)
760 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300761
762 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200763
764 out_free_memmap:
765 kfree(wl->target_mem_map);
766 wl->target_mem_map = NULL;
767
768 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300769}
770
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300771static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200772{
773 bool fw_ps;
774
775 /* only regulate station links */
776 if (hlid < WL1271_AP_STA_HLID_START)
777 return;
778
779 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
780
781 /*
782 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300783 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200784 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300785 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200786 wl1271_ps_link_end(wl, hlid);
787
788 /* Start high-level PS if the STA is asleep with enough blocks in FW */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300789 else if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200790 wl1271_ps_link_start(wl, hlid, true);
791}
792
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300793bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
794{
Arik Nemtsov04216da2011-08-14 13:17:38 +0300795 int id;
796
797 /* global/broadcast "stations" are always active */
798 if (hlid < WL1271_AP_STA_HLID_START)
799 return true;
800
801 id = hlid - WL1271_AP_STA_HLID_START;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300802 return test_bit(id, wl->ap_hlid_map);
803}
804
805static void wl12xx_irq_update_links_status(struct wl1271 *wl,
806 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200807{
808 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300809 u8 hlid, cnt;
810
811 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200812
813 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
814 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
815 wl1271_debug(DEBUG_PSM,
816 "link ps prev 0x%x cur 0x%x changed 0x%x",
817 wl->ap_fw_ps_map, cur_fw_ps_map,
818 wl->ap_fw_ps_map ^ cur_fw_ps_map);
819
820 wl->ap_fw_ps_map = cur_fw_ps_map;
821 }
822
823 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300824 if (!wl1271_is_active_sta(wl, hlid))
825 continue;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200826
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300827 cnt = status->tx_lnk_free_pkts[hlid] -
828 wl->links[hlid].prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200829
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300830 wl->links[hlid].prev_freed_pkts =
831 status->tx_lnk_free_pkts[hlid];
832 wl->links[hlid].allocated_pkts -= cnt;
833
834 wl12xx_irq_ps_regulate_link(wl, hlid,
835 wl->links[hlid].allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200836 }
837}
838
Eliad Peller4d56ad92011-08-14 13:17:05 +0300839static void wl12xx_fw_status(struct wl1271 *wl,
840 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300841{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200842 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200843 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300844 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300845 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846
Eliad Peller4d56ad92011-08-14 13:17:05 +0300847 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200848
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300849 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
850 "drv_rx_counter = %d, tx_results_counter = %d)",
851 status->intr,
852 status->fw_rx_counter,
853 status->drv_rx_counter,
854 status->tx_results_counter);
855
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300856 for (i = 0; i < NUM_TX_QUEUES; i++) {
857 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300858 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300859 (status->tx_released_pkts[i] -
860 wl->tx_pkts_freed[i]) & 0xff;
861
862 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
863 }
864
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300865 /* prevent wrap-around in total blocks counter */
866 if (likely(wl->tx_blocks_freed <=
867 le32_to_cpu(status->total_released_blks)))
868 freed_blocks = le32_to_cpu(status->total_released_blks) -
869 wl->tx_blocks_freed;
870 else
871 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
872 le32_to_cpu(status->total_released_blks);
873
Eliad Peller4d56ad92011-08-14 13:17:05 +0300874 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200875
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300876 wl->tx_allocated_blocks -= freed_blocks;
877
Eliad Peller4d56ad92011-08-14 13:17:05 +0300878 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200879
Eliad Peller4d56ad92011-08-14 13:17:05 +0300880 /*
881 * The FW might change the total number of TX memblocks before
882 * we get a notification about blocks being released. Thus, the
883 * available blocks calculation might yield a temporary result
884 * which is lower than the actual available blocks. Keeping in
885 * mind that only blocks that were allocated can be moved from
886 * TX to RX, tx_blocks_available should never decrease here.
887 */
888 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
889 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300890
Ido Yariva5225502010-10-12 14:49:10 +0200891 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200892 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200893 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300894
Eliad Peller4d56ad92011-08-14 13:17:05 +0300895 /* for AP update num of allocated TX blocks per link and ps status */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300896 if (wl->bss_type == BSS_TYPE_AP_BSS)
897 wl12xx_irq_update_links_status(wl, status);
Eliad Peller4d56ad92011-08-14 13:17:05 +0300898
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200900 getnstimeofday(&ts);
901 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
902 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300903}
904
Ido Yariva6208652011-03-01 15:14:41 +0200905static void wl1271_flush_deferred_work(struct wl1271 *wl)
906{
907 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200908
Ido Yariva6208652011-03-01 15:14:41 +0200909 /* Pass all received frames to the network stack */
910 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
911 ieee80211_rx_ni(wl->hw, skb);
912
913 /* Return sent skbs to the network stack */
914 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300915 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200916}
917
918static void wl1271_netstack_work(struct work_struct *work)
919{
920 struct wl1271 *wl =
921 container_of(work, struct wl1271, netstack_work);
922
923 do {
924 wl1271_flush_deferred_work(wl);
925 } while (skb_queue_len(&wl->deferred_rx_queue));
926}
927
928#define WL1271_IRQ_MAX_LOOPS 256
929
930irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300933 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200934 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200935 struct wl1271 *wl = (struct wl1271 *)cookie;
936 bool done = false;
937 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200938 unsigned long flags;
939
940 /* TX might be handled here, avoid redundant work */
941 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
942 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300943
Ido Yariv341b7cd2011-03-31 10:07:01 +0200944 /*
945 * In case edge triggered interrupt must be used, we cannot iterate
946 * more than once without introducing race conditions with the hardirq.
947 */
948 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
949 loopcount = 1;
950
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300951 mutex_lock(&wl->mutex);
952
953 wl1271_debug(DEBUG_IRQ, "IRQ work");
954
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200955 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956 goto out;
957
Ido Yariva6208652011-03-01 15:14:41 +0200958 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300959 if (ret < 0)
960 goto out;
961
Ido Yariva6208652011-03-01 15:14:41 +0200962 while (!done && loopcount--) {
963 /*
964 * In order to avoid a race with the hardirq, clear the flag
965 * before acknowledging the chip. Since the mutex is held,
966 * wl1271_ps_elp_wakeup cannot be called concurrently.
967 */
968 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
969 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200970
Eliad Peller4d56ad92011-08-14 13:17:05 +0300971 wl12xx_fw_status(wl, wl->fw_status);
972 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200973 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200974 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200975 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200976 continue;
977 }
978
Eliad Pellerccc83b02010-10-27 14:09:57 +0200979 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
980 wl1271_error("watchdog interrupt received! "
981 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300982 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200983
984 /* restarting the chip. ignore any other interrupt. */
985 goto out;
986 }
987
Ido Yariva6208652011-03-01 15:14:41 +0200988 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200989 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
990
Eliad Peller4d56ad92011-08-14 13:17:05 +0300991 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200992
Ido Yariva5225502010-10-12 14:49:10 +0200993 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200994 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200995 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300996 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200997 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200998 /*
999 * In order to avoid starvation of the TX path,
1000 * call the work function directly.
1001 */
1002 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +02001003 } else {
1004 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001005 }
1006
Ido Yariv8aad2462011-03-01 15:14:38 +02001007 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001008 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +02001009 (wl->tx_results_count & 0xff))
1010 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001011
1012 /* Make sure the deferred queues don't get too long */
1013 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1014 skb_queue_len(&wl->deferred_rx_queue);
1015 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1016 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001017 }
1018
1019 if (intr & WL1271_ACX_INTR_EVENT_A) {
1020 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1021 wl1271_event_handle(wl, 0);
1022 }
1023
1024 if (intr & WL1271_ACX_INTR_EVENT_B) {
1025 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1026 wl1271_event_handle(wl, 1);
1027 }
1028
1029 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1030 wl1271_debug(DEBUG_IRQ,
1031 "WL1271_ACX_INTR_INIT_COMPLETE");
1032
1033 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1034 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035 }
1036
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 wl1271_ps_elp_sleep(wl);
1038
1039out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001040 spin_lock_irqsave(&wl->wl_lock, flags);
1041 /* In case TX was not handled here, queue TX work */
1042 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1043 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001044 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001045 ieee80211_queue_work(wl->hw, &wl->tx_work);
1046 spin_unlock_irqrestore(&wl->wl_lock, flags);
1047
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001049
1050 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051}
Ido Yariva6208652011-03-01 15:14:41 +02001052EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001054static int wl1271_fetch_firmware(struct wl1271 *wl)
1055{
1056 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001057 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058 int ret;
1059
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001060 if (wl->chip.id == CHIP_ID_1283_PG20)
1061 fw_name = WL128X_FW_NAME;
1062 else
1063 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001064
1065 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1066
1067 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001068
1069 if (ret < 0) {
1070 wl1271_error("could not get firmware: %d", ret);
1071 return ret;
1072 }
1073
1074 if (fw->size % 4) {
1075 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1076 fw->size);
1077 ret = -EILSEQ;
1078 goto out;
1079 }
1080
Arik Nemtsov166d5042010-10-16 21:44:57 +02001081 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001083 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084
1085 if (!wl->fw) {
1086 wl1271_error("could not allocate memory for the firmware");
1087 ret = -ENOMEM;
1088 goto out;
1089 }
1090
1091 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001092 ret = 0;
1093
1094out:
1095 release_firmware(fw);
1096
1097 return ret;
1098}
1099
1100static int wl1271_fetch_nvs(struct wl1271 *wl)
1101{
1102 const struct firmware *fw;
1103 int ret;
1104
Shahar Levi5aa42342011-03-06 16:32:07 +02001105 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001106
1107 if (ret < 0) {
1108 wl1271_error("could not get nvs file: %d", ret);
1109 return ret;
1110 }
1111
Shahar Levibc765bf2011-03-06 16:32:10 +02001112 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001113
1114 if (!wl->nvs) {
1115 wl1271_error("could not allocate memory for the nvs file");
1116 ret = -ENOMEM;
1117 goto out;
1118 }
1119
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001120 wl->nvs_len = fw->size;
1121
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001122out:
1123 release_firmware(fw);
1124
1125 return ret;
1126}
1127
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001128void wl12xx_queue_recovery_work(struct wl1271 *wl)
1129{
1130 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1131 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1132}
1133
Ido Yariv95dac04f2011-06-06 14:57:06 +03001134size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1135{
1136 size_t len = 0;
1137
1138 /* The FW log is a length-value list, find where the log end */
1139 while (len < maxlen) {
1140 if (memblock[len] == 0)
1141 break;
1142 if (len + memblock[len] + 1 > maxlen)
1143 break;
1144 len += memblock[len] + 1;
1145 }
1146
1147 /* Make sure we have enough room */
1148 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1149
1150 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1151 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1152 wl->fwlog_size += len;
1153
1154 return len;
1155}
1156
1157static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1158{
1159 u32 addr;
1160 u32 first_addr;
1161 u8 *block;
1162
1163 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1164 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1165 (wl->conf.fwlog.mem_blocks == 0))
1166 return;
1167
1168 wl1271_info("Reading FW panic log");
1169
1170 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1171 if (!block)
1172 return;
1173
1174 /*
1175 * Make sure the chip is awake and the logger isn't active.
1176 * This might fail if the firmware hanged.
1177 */
1178 if (!wl1271_ps_elp_wakeup(wl))
1179 wl12xx_cmd_stop_fwlog(wl);
1180
1181 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001182 wl12xx_fw_status(wl, wl->fw_status);
1183 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001184 if (!first_addr)
1185 goto out;
1186
1187 /* Traverse the memory blocks linked list */
1188 addr = first_addr;
1189 do {
1190 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1191 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1192 false);
1193
1194 /*
1195 * Memory blocks are linked to one another. The first 4 bytes
1196 * of each memory block hold the hardware address of the next
1197 * one. The last memory block points to the first one.
1198 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001199 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001200 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1201 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1202 break;
1203 } while (addr && (addr != first_addr));
1204
1205 wake_up_interruptible(&wl->fwlog_waitq);
1206
1207out:
1208 kfree(block);
1209}
1210
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001211static void wl1271_recovery_work(struct work_struct *work)
1212{
1213 struct wl1271 *wl =
1214 container_of(work, struct wl1271, recovery_work);
1215
1216 mutex_lock(&wl->mutex);
1217
1218 if (wl->state != WL1271_STATE_ON)
1219 goto out;
1220
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001221 /* Avoid a recursive recovery */
1222 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1223
Ido Yariv95dac04f2011-06-06 14:57:06 +03001224 wl12xx_read_fwlog_panic(wl);
1225
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001226 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1227 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001228
Eliad Peller2a5bff02011-08-25 18:10:59 +03001229 BUG_ON(bug_on_recovery);
1230
Oz Krakowskib992c682011-06-26 10:36:02 +03001231 /*
1232 * Advance security sequence number to overcome potential progress
1233 * in the firmware during recovery. This doens't hurt if the network is
1234 * not encrypted.
1235 */
1236 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1237 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1238 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1239
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001240 /* Prevent spurious TX during FW restart */
1241 ieee80211_stop_queues(wl->hw);
1242
Luciano Coelho33c2c062011-05-10 14:46:02 +03001243 if (wl->sched_scanning) {
1244 ieee80211_sched_scan_stopped(wl->hw);
1245 wl->sched_scanning = false;
1246 }
1247
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001248 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001249 __wl1271_op_remove_interface(wl, false);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001250
1251 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1252
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001253 ieee80211_restart_hw(wl->hw);
1254
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001255 /*
1256 * Its safe to enable TX now - the queues are stopped after a request
1257 * to restart the HW.
1258 */
1259 ieee80211_wake_queues(wl->hw);
1260
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001261out:
1262 mutex_unlock(&wl->mutex);
1263}
1264
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001265static void wl1271_fw_wakeup(struct wl1271 *wl)
1266{
1267 u32 elp_reg;
1268
1269 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001270 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001271}
1272
1273static int wl1271_setup(struct wl1271 *wl)
1274{
1275 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1276 if (!wl->fw_status)
1277 return -ENOMEM;
1278
1279 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1280 if (!wl->tx_res_if) {
1281 kfree(wl->fw_status);
1282 return -ENOMEM;
1283 }
1284
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 return 0;
1286}
1287
1288static int wl1271_chip_wakeup(struct wl1271 *wl)
1289{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001290 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291 int ret = 0;
1292
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001293 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001294 ret = wl1271_power_on(wl);
1295 if (ret < 0)
1296 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001297 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001298 wl1271_io_reset(wl);
1299 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001300
1301 /* We don't need a real memory partition here, because we only want
1302 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001303 memset(&partition, 0, sizeof(partition));
1304 partition.reg.start = REGISTERS_BASE;
1305 partition.reg.size = REGISTERS_DOWN_SIZE;
1306 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001307
1308 /* ELP module wake up */
1309 wl1271_fw_wakeup(wl);
1310
1311 /* whal_FwCtrl_BootSm() */
1312
1313 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001314 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315
1316 /* 1. check if chip id is valid */
1317
1318 switch (wl->chip.id) {
1319 case CHIP_ID_1271_PG10:
1320 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1321 wl->chip.id);
1322
1323 ret = wl1271_setup(wl);
1324 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001325 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001326 break;
1327 case CHIP_ID_1271_PG20:
1328 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1329 wl->chip.id);
1330
Shahar Levi0c005042011-06-12 10:34:43 +03001331 /*
1332 * 'end-of-transaction flag' and 'LPD mode flag'
1333 * should be set in wl127x AP mode only
1334 */
Shahar Levi564f5952011-04-04 10:20:39 +03001335 if (wl->bss_type == BSS_TYPE_AP_BSS)
Shahar Levi0c005042011-06-12 10:34:43 +03001336 wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
1337 WL12XX_QUIRK_LPD_MODE);
Shahar Levi564f5952011-04-04 10:20:39 +03001338
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339 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
Arik Nemtsov166d5042010-10-16 21:44:57 +02001395 wl->bss_type = BSS_TYPE_STA_BSS;
1396
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001397 while (retries) {
1398 retries--;
1399 ret = wl1271_chip_wakeup(wl);
1400 if (ret < 0)
1401 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001403 ret = wl1271_boot(wl);
1404 if (ret < 0)
1405 goto power_off;
1406
1407 ret = wl1271_plt_init(wl);
1408 if (ret < 0)
1409 goto irq_disable;
1410
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001411 wl->state = WL1271_STATE_PLT;
1412 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001413 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001414
Gery Kahn6f07b722011-07-18 14:21:49 +03001415 /* update hw/fw version info in wiphy struct */
1416 wiphy->hw_version = wl->chip.id;
1417 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1418 sizeof(wiphy->fw_version));
1419
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420 goto out;
1421
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001422irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001423 mutex_unlock(&wl->mutex);
1424 /* Unlocking the mutex in the middle of handling is
1425 inherently unsafe. In this case we deem it safe to do,
1426 because we need to let any possibly pending IRQ out of
1427 the system (and while we are WL1271_STATE_OFF the IRQ
1428 work function will not do anything.) Also, any other
1429 possible concurrent operations will fail due to the
1430 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001431 wl1271_disable_interrupts(wl);
1432 wl1271_flush_deferred_work(wl);
1433 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001434 mutex_lock(&wl->mutex);
1435power_off:
1436 wl1271_power_off(wl);
1437 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001439 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1440 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441out:
1442 mutex_unlock(&wl->mutex);
1443
1444 return ret;
1445}
1446
Luciano Coelho4623ec72011-03-21 19:26:41 +02001447static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448{
1449 int ret = 0;
1450
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001451 wl1271_notice("power down");
1452
1453 if (wl->state != WL1271_STATE_PLT) {
1454 wl1271_error("cannot power down because not in PLT "
1455 "state: %d", wl->state);
1456 ret = -EBUSY;
1457 goto out;
1458 }
1459
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001460 wl1271_power_off(wl);
1461
1462 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001463 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001464
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001466 wl1271_disable_interrupts(wl);
1467 wl1271_flush_deferred_work(wl);
1468 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001469 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001470 mutex_lock(&wl->mutex);
1471out:
1472 return ret;
1473}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001474
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001475int wl1271_plt_stop(struct wl1271 *wl)
1476{
1477 int ret;
1478
1479 mutex_lock(&wl->mutex);
1480 ret = __wl1271_plt_stop(wl);
1481 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001482 return ret;
1483}
1484
Johannes Berg7bb45682011-02-24 14:42:06 +01001485static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486{
1487 struct wl1271 *wl = hw->priv;
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
1495 if (wl->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 */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001501 if (wl->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))
1558 wl1271_tx_work_locked(wl);
1559
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 Peller8a7cf3f2011-06-06 12:21:54 +03001615static int wl1271_configure_suspend_sta(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001616{
Eliad Pellere85d1622011-06-27 13:06:43 +03001617 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001618
Eliad Peller94390642011-05-13 11:57:13 +03001619 mutex_lock(&wl->mutex);
1620
Eliad Pellere85d1622011-06-27 13:06:43 +03001621 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1622 goto out_unlock;
1623
Eliad Peller94390642011-05-13 11:57:13 +03001624 ret = wl1271_ps_elp_wakeup(wl);
1625 if (ret < 0)
1626 goto out_unlock;
1627
1628 /* enter psm if needed*/
1629 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1630 DECLARE_COMPLETION_ONSTACK(compl);
1631
1632 wl->ps_compl = &compl;
1633 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1634 wl->basic_rate, true);
1635 if (ret < 0)
1636 goto out_sleep;
1637
1638 /* we must unlock here so we will be able to get events */
1639 wl1271_ps_elp_sleep(wl);
1640 mutex_unlock(&wl->mutex);
1641
1642 ret = wait_for_completion_timeout(
1643 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1644 if (ret <= 0) {
1645 wl1271_warning("couldn't enter ps mode!");
1646 ret = -EBUSY;
1647 goto out;
1648 }
1649
1650 /* take mutex again, and wakeup */
1651 mutex_lock(&wl->mutex);
1652
1653 ret = wl1271_ps_elp_wakeup(wl);
1654 if (ret < 0)
1655 goto out_unlock;
1656 }
1657out_sleep:
1658 wl1271_ps_elp_sleep(wl);
1659out_unlock:
1660 mutex_unlock(&wl->mutex);
1661out:
1662 return ret;
1663
1664}
1665
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001666static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001667{
Eliad Pellere85d1622011-06-27 13:06:43 +03001668 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001669
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001670 mutex_lock(&wl->mutex);
1671
Eliad Pellere85d1622011-06-27 13:06:43 +03001672 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1673 goto out_unlock;
1674
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001675 ret = wl1271_ps_elp_wakeup(wl);
1676 if (ret < 0)
1677 goto out_unlock;
1678
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001679 ret = wl1271_acx_beacon_filter_opt(wl, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001680
1681 wl1271_ps_elp_sleep(wl);
1682out_unlock:
1683 mutex_unlock(&wl->mutex);
1684 return ret;
1685
1686}
1687
1688static int wl1271_configure_suspend(struct wl1271 *wl)
1689{
1690 if (wl->bss_type == BSS_TYPE_STA_BSS)
1691 return wl1271_configure_suspend_sta(wl);
1692 if (wl->bss_type == BSS_TYPE_AP_BSS)
1693 return wl1271_configure_suspend_ap(wl);
1694 return 0;
1695}
1696
1697static void wl1271_configure_resume(struct wl1271 *wl)
1698{
1699 int ret;
1700 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1701 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1702
1703 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001704 return;
1705
1706 mutex_lock(&wl->mutex);
1707 ret = wl1271_ps_elp_wakeup(wl);
1708 if (ret < 0)
1709 goto out;
1710
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001711 if (is_sta) {
1712 /* exit psm if it wasn't configured */
1713 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1714 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1715 wl->basic_rate, true);
1716 } else if (is_ap) {
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001717 wl1271_acx_beacon_filter_opt(wl, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001718 }
Eliad Peller94390642011-05-13 11:57:13 +03001719
1720 wl1271_ps_elp_sleep(wl);
1721out:
1722 mutex_unlock(&wl->mutex);
1723}
1724
Eliad Peller402e48612011-05-13 11:57:09 +03001725static int wl1271_op_suspend(struct ieee80211_hw *hw,
1726 struct cfg80211_wowlan *wow)
1727{
1728 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001729 int ret;
1730
Eliad Peller402e48612011-05-13 11:57:09 +03001731 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001732 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001733
Eliad Peller4a859df2011-06-06 12:21:52 +03001734 wl->wow_enabled = true;
1735 ret = wl1271_configure_suspend(wl);
1736 if (ret < 0) {
1737 wl1271_warning("couldn't prepare device to suspend");
1738 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001739 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001740 /* flush any remaining work */
1741 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001742
1743 /*
1744 * disable and re-enable interrupts in order to flush
1745 * the threaded_irq
1746 */
1747 wl1271_disable_interrupts(wl);
1748
1749 /*
1750 * set suspended flag to avoid triggering a new threaded_irq
1751 * work. no need for spinlock as interrupts are disabled.
1752 */
1753 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1754
1755 wl1271_enable_interrupts(wl);
1756 flush_work(&wl->tx_work);
1757 flush_delayed_work(&wl->pspoll_work);
1758 flush_delayed_work(&wl->elp_work);
1759
Eliad Peller402e48612011-05-13 11:57:09 +03001760 return 0;
1761}
1762
1763static int wl1271_op_resume(struct ieee80211_hw *hw)
1764{
1765 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001766 unsigned long flags;
1767 bool run_irq_work = false;
1768
Eliad Peller402e48612011-05-13 11:57:09 +03001769 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1770 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001771 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001772
1773 /*
1774 * re-enable irq_work enqueuing, and call irq_work directly if
1775 * there is a pending work.
1776 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001777 spin_lock_irqsave(&wl->wl_lock, flags);
1778 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1779 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1780 run_irq_work = true;
1781 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001782
Eliad Peller4a859df2011-06-06 12:21:52 +03001783 if (run_irq_work) {
1784 wl1271_debug(DEBUG_MAC80211,
1785 "run postponed irq_work directly");
1786 wl1271_irq(0, wl);
1787 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001788 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001789 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001790 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001791
Eliad Peller402e48612011-05-13 11:57:09 +03001792 return 0;
1793}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001794#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001795
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001796static int wl1271_op_start(struct ieee80211_hw *hw)
1797{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001798 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1799
1800 /*
1801 * We have to delay the booting of the hardware because
1802 * we need to know the local MAC address before downloading and
1803 * initializing the firmware. The MAC address cannot be changed
1804 * after boot, and without the proper MAC address, the firmware
1805 * will not function properly.
1806 *
1807 * The MAC address is first known when the corresponding interface
1808 * is added. That is where we will initialize the hardware.
1809 */
1810
1811 return 0;
1812}
1813
1814static void wl1271_op_stop(struct ieee80211_hw *hw)
1815{
1816 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1817}
1818
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001819static u8 wl12xx_get_role_type(struct wl1271 *wl)
1820{
1821 switch (wl->bss_type) {
1822 case BSS_TYPE_AP_BSS:
1823 return WL1271_ROLE_AP;
1824
1825 case BSS_TYPE_STA_BSS:
1826 return WL1271_ROLE_STA;
1827
Eliad Peller227e81e2011-08-14 13:17:26 +03001828 case BSS_TYPE_IBSS:
1829 return WL1271_ROLE_IBSS;
1830
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001831 default:
1832 wl1271_error("invalid bss_type: %d", wl->bss_type);
1833 }
1834 return WL12XX_INVALID_ROLE_TYPE;
1835}
1836
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001837static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1838 struct ieee80211_vif *vif)
1839{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001840 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001841 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001842 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001843 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001844 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02001845 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001846
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001847 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1848 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849
1850 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001851 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001852 wl1271_debug(DEBUG_MAC80211,
1853 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001854 ret = -EBUSY;
1855 goto out;
1856 }
1857
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001858 /*
1859 * in some very corner case HW recovery scenarios its possible to
1860 * get here before __wl1271_op_remove_interface is complete, so
1861 * opt out if that is the case.
1862 */
1863 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1864 ret = -EBUSY;
1865 goto out;
1866 }
1867
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001868 switch (vif->type) {
1869 case NL80211_IFTYPE_STATION:
1870 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001871 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001872 break;
1873 case NL80211_IFTYPE_ADHOC:
1874 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001875 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001876 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001877 case NL80211_IFTYPE_AP:
1878 wl->bss_type = BSS_TYPE_AP_BSS;
1879 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001880 default:
1881 ret = -EOPNOTSUPP;
1882 goto out;
1883 }
1884
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001885 role_type = wl12xx_get_role_type(wl);
1886 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
1887 ret = -EINVAL;
1888 goto out;
1889 }
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001890 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001891
1892 if (wl->state != WL1271_STATE_OFF) {
1893 wl1271_error("cannot start because not in off state: %d",
1894 wl->state);
1895 ret = -EBUSY;
1896 goto out;
1897 }
1898
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001899 while (retries) {
1900 retries--;
1901 ret = wl1271_chip_wakeup(wl);
1902 if (ret < 0)
1903 goto power_off;
1904
1905 ret = wl1271_boot(wl);
1906 if (ret < 0)
1907 goto power_off;
1908
Eliad Peller227e81e2011-08-14 13:17:26 +03001909 if (wl->bss_type == BSS_TYPE_STA_BSS ||
1910 wl->bss_type == BSS_TYPE_IBSS) {
Eliad Peller04e80792011-08-14 13:17:09 +03001911 /*
1912 * The device role is a special role used for
1913 * rx and tx frames prior to association (as
1914 * the STA role can get packets only from
1915 * its associated bssid)
1916 */
1917 ret = wl12xx_cmd_role_enable(wl,
1918 WL1271_ROLE_DEVICE,
1919 &wl->dev_role_id);
1920 if (ret < 0)
1921 goto irq_disable;
1922 }
1923
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001924 ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id);
1925 if (ret < 0)
1926 goto irq_disable;
1927
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001928 ret = wl1271_hw_init(wl);
1929 if (ret < 0)
1930 goto irq_disable;
1931
Eliad Peller71125ab2010-10-28 21:46:43 +02001932 booted = true;
1933 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001934
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001935irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001936 mutex_unlock(&wl->mutex);
1937 /* Unlocking the mutex in the middle of handling is
1938 inherently unsafe. In this case we deem it safe to do,
1939 because we need to let any possibly pending IRQ out of
1940 the system (and while we are WL1271_STATE_OFF the IRQ
1941 work function will not do anything.) Also, any other
1942 possible concurrent operations will fail due to the
1943 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001944 wl1271_disable_interrupts(wl);
1945 wl1271_flush_deferred_work(wl);
1946 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001947 mutex_lock(&wl->mutex);
1948power_off:
1949 wl1271_power_off(wl);
1950 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001951
Eliad Peller71125ab2010-10-28 21:46:43 +02001952 if (!booted) {
1953 wl1271_error("firmware boot failed despite %d retries",
1954 WL1271_BOOT_RETRIES);
1955 goto out;
1956 }
1957
1958 wl->vif = vif;
1959 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001960 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001961 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001962
1963 /* update hw/fw version info in wiphy struct */
1964 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001965 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001966 sizeof(wiphy->fw_version));
1967
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001968 /*
1969 * Now we know if 11a is supported (info from the NVS), so disable
1970 * 11a channels if not supported
1971 */
1972 if (!wl->enable_11a)
1973 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1974
1975 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1976 wl->enable_11a ? "" : "not ");
1977
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001978out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001979 mutex_unlock(&wl->mutex);
1980
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001981 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001982 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001983 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001984 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001985
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001986 return ret;
1987}
1988
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001989static void __wl1271_op_remove_interface(struct wl1271 *wl,
1990 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001991{
Arik Nemtsovbf54e302011-08-14 13:17:32 +03001992 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001993
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001994 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001995
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001996 /* because of hardware recovery, we may get here twice */
1997 if (wl->state != WL1271_STATE_ON)
1998 return;
1999
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002000 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002001
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002002 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002003 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002004 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002005
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002006 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03002007 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002008 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002009
Luciano Coelho08688d62010-07-08 17:50:07 +03002010 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002011 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002012 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002013 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002014 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002015 }
2016
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002017 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2018 /* disable active roles */
2019 ret = wl1271_ps_elp_wakeup(wl);
2020 if (ret < 0)
2021 goto deinit;
2022
Eliad Peller04e80792011-08-14 13:17:09 +03002023 if (wl->bss_type == BSS_TYPE_STA_BSS) {
2024 ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
2025 if (ret < 0)
2026 goto deinit;
2027 }
2028
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002029 ret = wl12xx_cmd_role_disable(wl, &wl->role_id);
2030 if (ret < 0)
2031 goto deinit;
2032
2033 wl1271_ps_elp_sleep(wl);
2034 }
2035deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002036 /* clear all hlids (except system_hlid) */
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002037 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002038 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002039 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
2040 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002041
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002042 /*
2043 * this must be before the cancel_work calls below, so that the work
2044 * functions don't perform further work.
2045 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002046 wl->state = WL1271_STATE_OFF;
2047
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002048 mutex_unlock(&wl->mutex);
2049
Ido Yariva6208652011-03-01 15:14:41 +02002050 wl1271_disable_interrupts(wl);
2051 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02002052 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02002053 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002054 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03002055 del_timer_sync(&wl->rx_streaming_timer);
2056 cancel_work_sync(&wl->rx_streaming_enable_work);
2057 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002058 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02002059 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002060
2061 mutex_lock(&wl->mutex);
2062
2063 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002064 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002065 wl1271_power_off(wl);
2066
2067 memset(wl->bssid, 0, ETH_ALEN);
Johannes Berg3b40c042011-07-13 10:39:16 +02002068 memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002069 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002070 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002071 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002072 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002073
2074 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002075 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002076 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
2077 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002078 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002079 wl->tx_results_count = 0;
2080 wl->tx_packets_count = 0;
2081 wl->time_offset = 0;
2082 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002083 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002084 wl->vif = NULL;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002085 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002086 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002087 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02002088 wl->ap_fw_ps_map = 0;
2089 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002090 wl->sched_scanning = false;
Eliad Peller7f0979882011-08-14 13:17:06 +03002091 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002092 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerc690ec82011-08-14 13:17:07 +03002093 memset(wl->roles_map, 0, sizeof(wl->roles_map));
2094 memset(wl->links_map, 0, sizeof(wl->links_map));
Eliad Peller251c1772011-08-14 13:17:17 +03002095 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002096
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002097 /* The system link is always allocated */
2098 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
2099
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002100 /*
2101 * this is performed after the cancel_work calls and the associated
2102 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2103 * get executed before all these vars have been reset.
2104 */
2105 wl->flags = 0;
2106
Eliad Peller4d56ad92011-08-14 13:17:05 +03002107 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002108
Arik Nemtsov742246f2011-08-14 13:17:33 +03002109 for (i = 0; i < NUM_TX_QUEUES; i++) {
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002110 wl->tx_pkts_freed[i] = 0;
Arik Nemtsov742246f2011-08-14 13:17:33 +03002111 wl->tx_allocated_pkts[i] = 0;
2112 }
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002113
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002114 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002115
2116 kfree(wl->fw_status);
2117 wl->fw_status = NULL;
2118 kfree(wl->tx_res_if);
2119 wl->tx_res_if = NULL;
2120 kfree(wl->target_mem_map);
2121 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002122}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002123
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002124static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2125 struct ieee80211_vif *vif)
2126{
2127 struct wl1271 *wl = hw->priv;
2128
2129 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002130 /*
2131 * wl->vif can be null here if someone shuts down the interface
2132 * just when hardware recovery has been started.
2133 */
2134 if (wl->vif) {
2135 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002136 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002137 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002138
Juuso Oikarinen67353292010-11-18 15:19:02 +02002139 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002140 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002141}
2142
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002143static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002144{
2145 int ret;
Eliad Peller227e81e2011-08-14 13:17:26 +03002146 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002147
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002148 /*
2149 * One of the side effects of the JOIN command is that is clears
2150 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2151 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002152 * Currently the only valid scenario for JOIN during association
2153 * is on roaming, in which case we will also be given new keys.
2154 * Keep the below message for now, unless it starts bothering
2155 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002156 */
2157 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2158 wl1271_info("JOIN while associated.");
2159
2160 if (set_assoc)
2161 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2162
Eliad Peller227e81e2011-08-14 13:17:26 +03002163 if (is_ibss)
2164 ret = wl12xx_cmd_role_start_ibss(wl);
2165 else
2166 ret = wl12xx_cmd_role_start_sta(wl);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002167 if (ret < 0)
2168 goto out;
2169
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002170 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2171 goto out;
2172
2173 /*
2174 * The join command disable the keep-alive mode, shut down its process,
2175 * and also clear the template config, so we need to reset it all after
2176 * the join. The acx_aid starts the keep-alive process, and the order
2177 * of the commands below is relevant.
2178 */
2179 ret = wl1271_acx_keep_alive_mode(wl, true);
2180 if (ret < 0)
2181 goto out;
2182
2183 ret = wl1271_acx_aid(wl, wl->aid);
2184 if (ret < 0)
2185 goto out;
2186
2187 ret = wl1271_cmd_build_klv_null_data(wl);
2188 if (ret < 0)
2189 goto out;
2190
2191 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2192 ACX_KEEP_ALIVE_TPL_VALID);
2193 if (ret < 0)
2194 goto out;
2195
2196out:
2197 return ret;
2198}
2199
2200static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002201{
2202 int ret;
2203
2204 /* to stop listening to a channel, we disconnect */
Eliad Pellerc690ec82011-08-14 13:17:07 +03002205 ret = wl12xx_cmd_role_stop_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002206 if (ret < 0)
2207 goto out;
2208
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002209 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002210
Oz Krakowskib992c682011-06-26 10:36:02 +03002211 /* reset TX security counters on a clean disconnect */
2212 wl->tx_security_last_seq_lsb = 0;
2213 wl->tx_security_seq = 0;
2214
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002215out:
2216 return ret;
2217}
2218
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002219static void wl1271_set_band_rate(struct wl1271 *wl)
2220{
Eliad Peller53835a22011-08-23 15:56:23 +03002221 if (wl->band == IEEE80211_BAND_2GHZ) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002222 wl->basic_rate_set = wl->conf.tx.basic_rate;
Eliad Peller53835a22011-08-23 15:56:23 +03002223 wl->rate_set = wl->conf.tx.basic_rate;
2224 } else {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002225 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
Eliad Peller53835a22011-08-23 15:56:23 +03002226 wl->rate_set = wl->conf.tx.basic_rate_5;
2227 }
2228
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002229}
2230
Eliad Peller251c1772011-08-14 13:17:17 +03002231static bool wl12xx_is_roc(struct wl1271 *wl)
2232{
2233 u8 role_id;
2234
2235 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2236 if (role_id >= WL12XX_MAX_ROLES)
2237 return false;
2238
2239 return true;
2240}
2241
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002242static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002243{
2244 int ret;
2245
2246 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002247 /* no need to croc if we weren't busy (e.g. during boot) */
2248 if (wl12xx_is_roc(wl)) {
2249 ret = wl12xx_croc(wl, wl->dev_role_id);
2250 if (ret < 0)
2251 goto out;
2252
2253 ret = wl12xx_cmd_role_stop_dev(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002254 if (ret < 0)
2255 goto out;
2256 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002257 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002258 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002259 if (ret < 0)
2260 goto out;
2261 ret = wl1271_acx_keep_alive_config(
2262 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2263 ACX_KEEP_ALIVE_TPL_INVALID);
2264 if (ret < 0)
2265 goto out;
2266 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2267 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002268 /* The current firmware only supports sched_scan in idle */
2269 if (wl->sched_scanning) {
2270 wl1271_scan_sched_scan_stop(wl);
2271 ieee80211_sched_scan_stopped(wl->hw);
2272 }
2273
Eliad Peller251c1772011-08-14 13:17:17 +03002274 ret = wl12xx_cmd_role_start_dev(wl);
2275 if (ret < 0)
2276 goto out;
2277
2278 ret = wl12xx_roc(wl, wl->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002279 if (ret < 0)
2280 goto out;
2281 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2282 }
2283
2284out:
2285 return ret;
2286}
2287
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002288static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2289{
2290 struct wl1271 *wl = hw->priv;
2291 struct ieee80211_conf *conf = &hw->conf;
2292 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002293 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002294
2295 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2296
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002297 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2298 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002299 channel,
2300 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002301 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002302 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2303 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002304
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002305 /*
2306 * mac80211 will go to idle nearly immediately after transmitting some
2307 * frames, such as the deauth. To make sure those frames reach the air,
2308 * wait here until the TX queue is fully flushed.
2309 */
2310 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2311 (conf->flags & IEEE80211_CONF_IDLE))
2312 wl1271_tx_flush(wl);
2313
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002314 mutex_lock(&wl->mutex);
2315
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002316 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002317 /* we support configuring the channel and band while off */
2318 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2319 wl->band = conf->channel->band;
2320 wl->channel = channel;
2321 }
2322
Arik Nemtsov097f8822011-06-27 22:06:34 +03002323 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2324 wl->power_level = conf->power_level;
2325
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002326 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002327 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002328
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002329 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2330
Ido Yariva6208652011-03-01 15:14:41 +02002331 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002332 if (ret < 0)
2333 goto out;
2334
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002335 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002336 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2337 ((wl->band != conf->channel->band) ||
2338 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002339 wl->band = conf->channel->band;
2340 wl->channel = channel;
2341
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002342 if (!is_ap) {
2343 /*
2344 * FIXME: the mac80211 should really provide a fixed
2345 * rate to use here. for now, just use the smallest
2346 * possible rate for the band as a fixed rate for
2347 * association frames and other control messages.
2348 */
2349 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2350 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002351
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002352 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2353 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002354 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002355 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002356 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002357
Eliad Peller251c1772011-08-14 13:17:17 +03002358 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2359 if (wl12xx_is_roc(wl)) {
2360 /* roaming */
2361 ret = wl12xx_croc(wl, wl->dev_role_id);
2362 if (ret < 0)
2363 goto out_sleep;
2364 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002365 ret = wl1271_join(wl, false);
2366 if (ret < 0)
2367 wl1271_warning("cmd join on channel "
2368 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002369 } else {
2370 /*
2371 * change the ROC channel. do it only if we are
2372 * not idle. otherwise, CROC will be called
2373 * anyway.
2374 */
2375 if (wl12xx_is_roc(wl) &&
2376 !(conf->flags & IEEE80211_CONF_IDLE)) {
2377 ret = wl12xx_croc(wl, wl->dev_role_id);
2378 if (ret < 0)
2379 goto out_sleep;
2380
2381 ret = wl12xx_roc(wl, wl->dev_role_id);
2382 if (ret < 0)
2383 wl1271_warning("roc failed %d",
2384 ret);
2385 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002386 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002387 }
2388 }
2389
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002390 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2391 ret = wl1271_sta_handle_idle(wl,
2392 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002393 if (ret < 0)
2394 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002395 }
2396
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002397 /*
2398 * if mac80211 changes the PSM mode, make sure the mode is not
2399 * incorrectly changed after the pspoll failure active window.
2400 */
2401 if (changed & IEEE80211_CONF_CHANGE_PS)
2402 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2403
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002404 if (conf->flags & IEEE80211_CONF_PS &&
2405 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2406 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002407
2408 /*
2409 * We enter PSM only if we're already associated.
2410 * If we're not, we'll enter it when joining an SSID,
2411 * through the bss_info_changed() hook.
2412 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002413 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002414 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002415 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002416 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002417 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002418 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002419 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002420 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002421
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002422 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002423
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002424 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002425 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002426 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002427 }
2428
2429 if (conf->power_level != wl->power_level) {
2430 ret = wl1271_acx_tx_power(wl, conf->power_level);
2431 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002432 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002433
2434 wl->power_level = conf->power_level;
2435 }
2436
2437out_sleep:
2438 wl1271_ps_elp_sleep(wl);
2439
2440out:
2441 mutex_unlock(&wl->mutex);
2442
2443 return ret;
2444}
2445
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002446struct wl1271_filter_params {
2447 bool enabled;
2448 int mc_list_length;
2449 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2450};
2451
Jiri Pirko22bedad2010-04-01 21:22:57 +00002452static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2453 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002454{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002455 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002456 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002457 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002458
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002459 if (unlikely(wl->state == WL1271_STATE_OFF))
2460 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002461
Juuso Oikarinen74441132009-10-13 12:47:53 +03002462 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002463 if (!fp) {
2464 wl1271_error("Out of memory setting filters.");
2465 return 0;
2466 }
2467
2468 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002469 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002470 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2471 fp->enabled = false;
2472 } else {
2473 fp->enabled = true;
2474 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002475 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002476 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002477 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002478 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002479 }
2480
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002481 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002482}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002483
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002484#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2485 FIF_ALLMULTI | \
2486 FIF_FCSFAIL | \
2487 FIF_BCN_PRBRESP_PROMISC | \
2488 FIF_CONTROL | \
2489 FIF_OTHER_BSS)
2490
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002491static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2492 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002493 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002494{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002495 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002496 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002497 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002498
Arik Nemtsov7d057862010-10-16 19:25:35 +02002499 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2500 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002501
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002502 mutex_lock(&wl->mutex);
2503
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002504 *total &= WL1271_SUPPORTED_FILTERS;
2505 changed &= WL1271_SUPPORTED_FILTERS;
2506
2507 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002508 goto out;
2509
Ido Yariva6208652011-03-01 15:14:41 +02002510 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002511 if (ret < 0)
2512 goto out;
2513
Arik Nemtsov7d057862010-10-16 19:25:35 +02002514 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2515 if (*total & FIF_ALLMULTI)
2516 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2517 else if (fp)
2518 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2519 fp->mc_list,
2520 fp->mc_list_length);
2521 if (ret < 0)
2522 goto out_sleep;
2523 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002524
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002525 /*
2526 * the fw doesn't provide an api to configure the filters. instead,
2527 * the filters configuration is based on the active roles / ROC
2528 * state.
2529 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002530
2531out_sleep:
2532 wl1271_ps_elp_sleep(wl);
2533
2534out:
2535 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002536 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002537}
2538
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002539static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2540 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2541 u16 tx_seq_16)
2542{
2543 struct wl1271_ap_key *ap_key;
2544 int i;
2545
2546 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2547
2548 if (key_size > MAX_KEY_SIZE)
2549 return -EINVAL;
2550
2551 /*
2552 * Find next free entry in ap_keys. Also check we are not replacing
2553 * an existing key.
2554 */
2555 for (i = 0; i < MAX_NUM_KEYS; i++) {
2556 if (wl->recorded_ap_keys[i] == NULL)
2557 break;
2558
2559 if (wl->recorded_ap_keys[i]->id == id) {
2560 wl1271_warning("trying to record key replacement");
2561 return -EINVAL;
2562 }
2563 }
2564
2565 if (i == MAX_NUM_KEYS)
2566 return -EBUSY;
2567
2568 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2569 if (!ap_key)
2570 return -ENOMEM;
2571
2572 ap_key->id = id;
2573 ap_key->key_type = key_type;
2574 ap_key->key_size = key_size;
2575 memcpy(ap_key->key, key, key_size);
2576 ap_key->hlid = hlid;
2577 ap_key->tx_seq_32 = tx_seq_32;
2578 ap_key->tx_seq_16 = tx_seq_16;
2579
2580 wl->recorded_ap_keys[i] = ap_key;
2581 return 0;
2582}
2583
2584static void wl1271_free_ap_keys(struct wl1271 *wl)
2585{
2586 int i;
2587
2588 for (i = 0; i < MAX_NUM_KEYS; i++) {
2589 kfree(wl->recorded_ap_keys[i]);
2590 wl->recorded_ap_keys[i] = NULL;
2591 }
2592}
2593
2594static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2595{
2596 int i, ret = 0;
2597 struct wl1271_ap_key *key;
2598 bool wep_key_added = false;
2599
2600 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002601 u8 hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002602 if (wl->recorded_ap_keys[i] == NULL)
2603 break;
2604
2605 key = wl->recorded_ap_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002606 hlid = key->hlid;
2607 if (hlid == WL12XX_INVALID_LINK_ID)
2608 hlid = wl->ap_bcast_hlid;
2609
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002610 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2611 key->id, key->key_type,
2612 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002613 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002614 key->tx_seq_16);
2615 if (ret < 0)
2616 goto out;
2617
2618 if (key->key_type == KEY_WEP)
2619 wep_key_added = true;
2620 }
2621
2622 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002623 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002624 wl->ap_bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002625 if (ret < 0)
2626 goto out;
2627 }
2628
2629out:
2630 wl1271_free_ap_keys(wl);
2631 return ret;
2632}
2633
2634static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2635 u8 key_size, const u8 *key, u32 tx_seq_32,
2636 u16 tx_seq_16, struct ieee80211_sta *sta)
2637{
2638 int ret;
2639 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2640
2641 if (is_ap) {
2642 struct wl1271_station *wl_sta;
2643 u8 hlid;
2644
2645 if (sta) {
2646 wl_sta = (struct wl1271_station *)sta->drv_priv;
2647 hlid = wl_sta->hlid;
2648 } else {
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002649 hlid = wl->ap_bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002650 }
2651
2652 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2653 /*
2654 * We do not support removing keys after AP shutdown.
2655 * Pretend we do to make mac80211 happy.
2656 */
2657 if (action != KEY_ADD_OR_REPLACE)
2658 return 0;
2659
2660 ret = wl1271_record_ap_key(wl, id,
2661 key_type, key_size,
2662 key, hlid, tx_seq_32,
2663 tx_seq_16);
2664 } else {
2665 ret = wl1271_cmd_set_ap_key(wl, action,
2666 id, key_type, key_size,
2667 key, hlid, tx_seq_32,
2668 tx_seq_16);
2669 }
2670
2671 if (ret < 0)
2672 return ret;
2673 } else {
2674 const u8 *addr;
2675 static const u8 bcast_addr[ETH_ALEN] = {
2676 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2677 };
2678
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002679 /*
2680 * A STA set to GEM cipher requires 2 tx spare blocks.
2681 * Return to default value when GEM cipher key is removed
2682 */
2683 if (key_type == KEY_GEM) {
2684 if (action == KEY_ADD_OR_REPLACE)
2685 wl->tx_spare_blocks = 2;
2686 else if (action == KEY_REMOVE)
2687 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2688 }
2689
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002690 addr = sta ? sta->addr : bcast_addr;
2691
2692 if (is_zero_ether_addr(addr)) {
2693 /* We dont support TX only encryption */
2694 return -EOPNOTSUPP;
2695 }
2696
2697 /* The wl1271 does not allow to remove unicast keys - they
2698 will be cleared automatically on next CMD_JOIN. Ignore the
2699 request silently, as we dont want the mac80211 to emit
2700 an error message. */
2701 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2702 return 0;
2703
Eliad Peller010d3d32011-08-14 13:17:31 +03002704 /* don't remove key if hlid was already deleted */
2705 if (action == KEY_REMOVE &&
2706 wl->sta_hlid == WL12XX_INVALID_LINK_ID)
2707 return 0;
2708
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002709 ret = wl1271_cmd_set_sta_key(wl, action,
2710 id, key_type, key_size,
2711 key, addr, tx_seq_32,
2712 tx_seq_16);
2713 if (ret < 0)
2714 return ret;
2715
2716 /* the default WEP key needs to be configured at least once */
2717 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002718 ret = wl12xx_cmd_set_default_wep_key(wl,
2719 wl->default_key,
2720 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002721 if (ret < 0)
2722 return ret;
2723 }
2724 }
2725
2726 return 0;
2727}
2728
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002729static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2730 struct ieee80211_vif *vif,
2731 struct ieee80211_sta *sta,
2732 struct ieee80211_key_conf *key_conf)
2733{
2734 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002735 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002736 u32 tx_seq_32 = 0;
2737 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002738 u8 key_type;
2739
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002740 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2741
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002742 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002743 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002744 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002745 key_conf->keylen, key_conf->flags);
2746 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2747
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002748 mutex_lock(&wl->mutex);
2749
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002750 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2751 ret = -EAGAIN;
2752 goto out_unlock;
2753 }
2754
Ido Yariva6208652011-03-01 15:14:41 +02002755 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002756 if (ret < 0)
2757 goto out_unlock;
2758
Johannes Berg97359d12010-08-10 09:46:38 +02002759 switch (key_conf->cipher) {
2760 case WLAN_CIPHER_SUITE_WEP40:
2761 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002762 key_type = KEY_WEP;
2763
2764 key_conf->hw_key_idx = key_conf->keyidx;
2765 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002766 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002767 key_type = KEY_TKIP;
2768
2769 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002770 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2771 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002772 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002773 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002774 key_type = KEY_AES;
2775
2776 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002777 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2778 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002779 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002780 case WL1271_CIPHER_SUITE_GEM:
2781 key_type = KEY_GEM;
2782 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2783 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2784 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002785 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002786 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002787
2788 ret = -EOPNOTSUPP;
2789 goto out_sleep;
2790 }
2791
2792 switch (cmd) {
2793 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002794 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2795 key_conf->keyidx, key_type,
2796 key_conf->keylen, key_conf->key,
2797 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002798 if (ret < 0) {
2799 wl1271_error("Could not add or replace key");
2800 goto out_sleep;
2801 }
2802 break;
2803
2804 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002805 ret = wl1271_set_key(wl, KEY_REMOVE,
2806 key_conf->keyidx, key_type,
2807 key_conf->keylen, key_conf->key,
2808 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002809 if (ret < 0) {
2810 wl1271_error("Could not remove key");
2811 goto out_sleep;
2812 }
2813 break;
2814
2815 default:
2816 wl1271_error("Unsupported key cmd 0x%x", cmd);
2817 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002818 break;
2819 }
2820
2821out_sleep:
2822 wl1271_ps_elp_sleep(wl);
2823
2824out_unlock:
2825 mutex_unlock(&wl->mutex);
2826
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002827 return ret;
2828}
2829
2830static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002831 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002832 struct cfg80211_scan_request *req)
2833{
2834 struct wl1271 *wl = hw->priv;
2835 int ret;
2836 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002837 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002838
2839 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2840
2841 if (req->n_ssids) {
2842 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002843 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002844 }
2845
2846 mutex_lock(&wl->mutex);
2847
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002848 if (wl->state == WL1271_STATE_OFF) {
2849 /*
2850 * We cannot return -EBUSY here because cfg80211 will expect
2851 * a call to ieee80211_scan_completed if we do - in this case
2852 * there won't be any call.
2853 */
2854 ret = -EAGAIN;
2855 goto out;
2856 }
2857
Ido Yariva6208652011-03-01 15:14:41 +02002858 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002859 if (ret < 0)
2860 goto out;
2861
Eliad Peller251c1772011-08-14 13:17:17 +03002862 /* cancel ROC before scanning */
2863 if (wl12xx_is_roc(wl)) {
2864 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2865 /* don't allow scanning right now */
2866 ret = -EBUSY;
2867 goto out_sleep;
2868 }
2869 wl12xx_croc(wl, wl->dev_role_id);
2870 wl12xx_cmd_role_stop_dev(wl);
2871 }
2872
Luciano Coelho5924f892010-08-04 03:46:22 +03002873 ret = wl1271_scan(hw->priv, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002874out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002875 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002876out:
2877 mutex_unlock(&wl->mutex);
2878
2879 return ret;
2880}
2881
Eliad Peller73ecce32011-06-27 13:06:45 +03002882static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2883 struct ieee80211_vif *vif)
2884{
2885 struct wl1271 *wl = hw->priv;
2886 int ret;
2887
2888 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2889
2890 mutex_lock(&wl->mutex);
2891
2892 if (wl->state == WL1271_STATE_OFF)
2893 goto out;
2894
2895 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2896 goto out;
2897
2898 ret = wl1271_ps_elp_wakeup(wl);
2899 if (ret < 0)
2900 goto out;
2901
2902 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2903 ret = wl1271_scan_stop(wl);
2904 if (ret < 0)
2905 goto out_sleep;
2906 }
2907 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2908 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
2909 wl->scan.req = NULL;
2910 ieee80211_scan_completed(wl->hw, true);
2911
2912out_sleep:
2913 wl1271_ps_elp_sleep(wl);
2914out:
2915 mutex_unlock(&wl->mutex);
2916
2917 cancel_delayed_work_sync(&wl->scan_complete_work);
2918}
2919
Luciano Coelho33c2c062011-05-10 14:46:02 +03002920static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2921 struct ieee80211_vif *vif,
2922 struct cfg80211_sched_scan_request *req,
2923 struct ieee80211_sched_scan_ies *ies)
2924{
2925 struct wl1271 *wl = hw->priv;
2926 int ret;
2927
2928 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2929
2930 mutex_lock(&wl->mutex);
2931
2932 ret = wl1271_ps_elp_wakeup(wl);
2933 if (ret < 0)
2934 goto out;
2935
2936 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2937 if (ret < 0)
2938 goto out_sleep;
2939
2940 ret = wl1271_scan_sched_scan_start(wl);
2941 if (ret < 0)
2942 goto out_sleep;
2943
2944 wl->sched_scanning = true;
2945
2946out_sleep:
2947 wl1271_ps_elp_sleep(wl);
2948out:
2949 mutex_unlock(&wl->mutex);
2950 return ret;
2951}
2952
2953static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2954 struct ieee80211_vif *vif)
2955{
2956 struct wl1271 *wl = hw->priv;
2957 int ret;
2958
2959 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2960
2961 mutex_lock(&wl->mutex);
2962
2963 ret = wl1271_ps_elp_wakeup(wl);
2964 if (ret < 0)
2965 goto out;
2966
2967 wl1271_scan_sched_scan_stop(wl);
2968
2969 wl1271_ps_elp_sleep(wl);
2970out:
2971 mutex_unlock(&wl->mutex);
2972}
2973
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002974static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2975{
2976 struct wl1271 *wl = hw->priv;
2977 int ret = 0;
2978
2979 mutex_lock(&wl->mutex);
2980
2981 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2982 ret = -EAGAIN;
2983 goto out;
2984 }
2985
Ido Yariva6208652011-03-01 15:14:41 +02002986 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002987 if (ret < 0)
2988 goto out;
2989
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002990 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002991 if (ret < 0)
2992 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2993
2994 wl1271_ps_elp_sleep(wl);
2995
2996out:
2997 mutex_unlock(&wl->mutex);
2998
2999 return ret;
3000}
3001
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003002static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3003{
3004 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003005 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003006
3007 mutex_lock(&wl->mutex);
3008
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003009 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3010 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003011 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003012 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003013
Ido Yariva6208652011-03-01 15:14:41 +02003014 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003015 if (ret < 0)
3016 goto out;
3017
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003018 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003019 if (ret < 0)
3020 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
3021
3022 wl1271_ps_elp_sleep(wl);
3023
3024out:
3025 mutex_unlock(&wl->mutex);
3026
3027 return ret;
3028}
3029
Arik Nemtsove78a2872010-10-16 19:07:21 +02003030static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003031 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003032{
Eliad Peller889cb362011-05-01 09:56:45 +03003033 u8 ssid_len;
3034 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3035 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003036
Eliad Peller889cb362011-05-01 09:56:45 +03003037 if (!ptr) {
3038 wl1271_error("No SSID in IEs!");
3039 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003040 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003041
Eliad Peller889cb362011-05-01 09:56:45 +03003042 ssid_len = ptr[1];
3043 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3044 wl1271_error("SSID is too long!");
3045 return -EINVAL;
3046 }
3047
3048 wl->ssid_len = ssid_len;
3049 memcpy(wl->ssid, ptr+2, ssid_len);
3050 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003051}
3052
Arik Nemtsove78a2872010-10-16 19:07:21 +02003053static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
3054 struct ieee80211_bss_conf *bss_conf,
3055 u32 changed)
3056{
3057 int ret = 0;
3058
3059 if (changed & BSS_CHANGED_ERP_SLOT) {
3060 if (bss_conf->use_short_slot)
3061 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
3062 else
3063 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
3064 if (ret < 0) {
3065 wl1271_warning("Set slot time failed %d", ret);
3066 goto out;
3067 }
3068 }
3069
3070 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3071 if (bss_conf->use_short_preamble)
3072 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
3073 else
3074 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
3075 }
3076
3077 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3078 if (bss_conf->use_cts_prot)
3079 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
3080 else
3081 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
3082 if (ret < 0) {
3083 wl1271_warning("Set ctsprotect failed %d", ret);
3084 goto out;
3085 }
3086 }
3087
3088out:
3089 return ret;
3090}
3091
3092static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3093 struct ieee80211_vif *vif,
3094 struct ieee80211_bss_conf *bss_conf,
3095 u32 changed)
3096{
3097 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3098 int ret = 0;
3099
3100 if ((changed & BSS_CHANGED_BEACON_INT)) {
3101 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3102 bss_conf->beacon_int);
3103
3104 wl->beacon_int = bss_conf->beacon_int;
3105 }
3106
3107 if ((changed & BSS_CHANGED_BEACON)) {
3108 struct ieee80211_hdr *hdr;
3109 int ieoffset = offsetof(struct ieee80211_mgmt,
3110 u.beacon.variable);
3111 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3112 u16 tmpl_id;
3113
3114 if (!beacon)
3115 goto out;
3116
3117 wl1271_debug(DEBUG_MASTER, "beacon updated");
3118
3119 ret = wl1271_ssid_set(wl, beacon, ieoffset);
3120 if (ret < 0) {
3121 dev_kfree_skb(beacon);
3122 goto out;
3123 }
3124 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3125 CMD_TEMPL_BEACON;
3126 ret = wl1271_cmd_template_set(wl, tmpl_id,
3127 beacon->data,
3128 beacon->len, 0,
3129 wl1271_tx_min_rate_get(wl));
3130 if (ret < 0) {
3131 dev_kfree_skb(beacon);
3132 goto out;
3133 }
3134
3135 hdr = (struct ieee80211_hdr *) beacon->data;
3136 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3137 IEEE80211_STYPE_PROBE_RESP);
3138
3139 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
3140 CMD_TEMPL_PROBE_RESPONSE;
3141 ret = wl1271_cmd_template_set(wl,
3142 tmpl_id,
3143 beacon->data,
3144 beacon->len, 0,
3145 wl1271_tx_min_rate_get(wl));
3146 dev_kfree_skb(beacon);
3147 if (ret < 0)
3148 goto out;
3149 }
3150
3151out:
3152 return ret;
3153}
3154
3155/* AP mode changes */
3156static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003157 struct ieee80211_vif *vif,
3158 struct ieee80211_bss_conf *bss_conf,
3159 u32 changed)
3160{
Arik Nemtsove78a2872010-10-16 19:07:21 +02003161 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003162
Arik Nemtsove78a2872010-10-16 19:07:21 +02003163 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3164 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003165
Arik Nemtsove78a2872010-10-16 19:07:21 +02003166 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
3167 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003168
Arik Nemtsov70f47422011-04-18 14:15:25 +03003169 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003170 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003171 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003172 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003173 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003174
3175 ret = wl1271_ap_init_templates(wl);
3176 if (ret < 0)
3177 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003178 }
3179
Arik Nemtsove78a2872010-10-16 19:07:21 +02003180 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3181 if (ret < 0)
3182 goto out;
3183
3184 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3185 if (bss_conf->enable_beacon) {
3186 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003187 ret = wl12xx_cmd_role_start_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003188 if (ret < 0)
3189 goto out;
3190
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003191 ret = wl1271_ap_init_hwenc(wl);
3192 if (ret < 0)
3193 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003194
3195 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3196 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003197 }
3198 } else {
3199 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003200 ret = wl12xx_cmd_role_stop_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003201 if (ret < 0)
3202 goto out;
3203
3204 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3205 wl1271_debug(DEBUG_AP, "stopped AP");
3206 }
3207 }
3208 }
3209
3210 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3211 if (ret < 0)
3212 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003213
3214 /* Handle HT information change */
3215 if ((changed & BSS_CHANGED_HT) &&
3216 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3217 ret = wl1271_acx_set_ht_information(wl,
3218 bss_conf->ht_operation_mode);
3219 if (ret < 0) {
3220 wl1271_warning("Set ht information failed %d", ret);
3221 goto out;
3222 }
3223 }
3224
Arik Nemtsove78a2872010-10-16 19:07:21 +02003225out:
3226 return;
3227}
3228
3229/* STA/IBSS mode changes */
3230static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3231 struct ieee80211_vif *vif,
3232 struct ieee80211_bss_conf *bss_conf,
3233 u32 changed)
3234{
3235 bool do_join = false, set_assoc = false;
3236 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003237 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003238 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003239 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003240 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003241 bool sta_exists = false;
3242 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003243
3244 if (is_ibss) {
3245 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3246 changed);
3247 if (ret < 0)
3248 goto out;
3249 }
3250
Eliad Peller227e81e2011-08-14 13:17:26 +03003251 if (changed & BSS_CHANGED_IBSS) {
3252 if (bss_conf->ibss_joined) {
3253 set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
3254 ibss_joined = true;
3255 } else {
3256 if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
3257 &wl->flags)) {
3258 wl1271_unjoin(wl);
3259 wl12xx_cmd_role_start_dev(wl);
3260 wl12xx_roc(wl, wl->dev_role_id);
3261 }
3262 }
3263 }
3264
3265 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003266 do_join = true;
3267
3268 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003269 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003270 do_join = true;
3271
Eliad Peller227e81e2011-08-14 13:17:26 +03003272 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003273 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3274 bss_conf->enable_beacon ? "enabled" : "disabled");
3275
3276 if (bss_conf->enable_beacon)
3277 wl->set_bss_type = BSS_TYPE_IBSS;
3278 else
3279 wl->set_bss_type = BSS_TYPE_STA_BSS;
3280 do_join = true;
3281 }
3282
Arik Nemtsove78a2872010-10-16 19:07:21 +02003283 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003284 bool enable = false;
3285 if (bss_conf->cqm_rssi_thold)
3286 enable = true;
3287 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3288 bss_conf->cqm_rssi_thold,
3289 bss_conf->cqm_rssi_hyst);
3290 if (ret < 0)
3291 goto out;
3292 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3293 }
3294
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003295 if ((changed & BSS_CHANGED_BSSID) &&
3296 /*
3297 * Now we know the correct bssid, so we send a new join command
3298 * and enable the BSSID filter
3299 */
3300 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003301 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003302
Eliad Pellerfa287b82010-12-26 09:27:50 +01003303 if (!is_zero_ether_addr(wl->bssid)) {
3304 ret = wl1271_cmd_build_null_data(wl);
3305 if (ret < 0)
3306 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003307
Eliad Pellerfa287b82010-12-26 09:27:50 +01003308 ret = wl1271_build_qos_null_data(wl);
3309 if (ret < 0)
3310 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003311
Eliad Pellerfa287b82010-12-26 09:27:50 +01003312 /* Need to update the BSSID (for filtering etc) */
3313 do_join = true;
3314 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003315 }
3316
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003317 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3318 rcu_read_lock();
3319 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3320 if (!sta)
3321 goto sta_not_found;
3322
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003323 /* save the supp_rates of the ap */
3324 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3325 if (sta->ht_cap.ht_supported)
3326 sta_rate_set |=
3327 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003328 sta_ht_cap = sta->ht_cap;
3329 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003330
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003331sta_not_found:
3332 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003333 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003334
Arik Nemtsove78a2872010-10-16 19:07:21 +02003335 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003336 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003337 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003338 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003339 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003340 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003341
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003342 wl->ps_poll_failures = 0;
3343
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003344 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003345 * use basic rates from AP, and determine lowest rate
3346 * to use with control frames.
3347 */
3348 rates = bss_conf->basic_rates;
3349 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3350 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003351 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003352 if (sta_rate_set)
3353 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
3354 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003355 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003356 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003357 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003358
3359 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003360 * with wl1271, we don't need to update the
3361 * beacon_int and dtim_period, because the firmware
3362 * updates it by itself when the first beacon is
3363 * received after a join.
3364 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003365 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3366 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003367 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003368
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003369 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003370 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003371 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003372 dev_kfree_skb(wl->probereq);
3373 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3374 ieoffset = offsetof(struct ieee80211_mgmt,
3375 u.probe_req.variable);
3376 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003377
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003378 /* enable the connection monitoring feature */
3379 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003380 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003381 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003382 } else {
3383 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003384 bool was_assoc =
3385 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3386 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003387 bool was_ifup =
3388 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3389 &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003390 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003391
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003392 /* free probe-request template */
3393 dev_kfree_skb(wl->probereq);
3394 wl->probereq = NULL;
3395
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003396 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003397 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003398
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003399 /* revert back to minimum rates for the current band */
3400 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003401 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003402 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003403 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003404 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003405
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003406 /* disable connection monitor features */
3407 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003408
3409 /* Disable the keep-alive feature */
3410 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003411 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003412 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003413
3414 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003415 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003416 u32 conf_flags = wl->hw->conf.flags;
3417 /*
3418 * we might have to disable roc, if there was
3419 * no IF_OPER_UP notification.
3420 */
3421 if (!was_ifup) {
3422 ret = wl12xx_croc(wl, wl->role_id);
3423 if (ret < 0)
3424 goto out;
3425 }
3426 /*
3427 * (we also need to disable roc in case of
3428 * roaming on the same channel. until we will
3429 * have a better flow...)
3430 */
3431 if (test_bit(wl->dev_role_id, wl->roc_map)) {
3432 ret = wl12xx_croc(wl, wl->dev_role_id);
3433 if (ret < 0)
3434 goto out;
3435 }
3436
Eliad Peller30df14d2011-04-05 19:13:28 +03003437 wl1271_unjoin(wl);
Eliad Peller251c1772011-08-14 13:17:17 +03003438 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
3439 wl12xx_cmd_role_start_dev(wl);
3440 wl12xx_roc(wl, wl->dev_role_id);
3441 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003442 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003443 }
3444 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003445
Eliad Pellerd192d262011-05-24 14:33:08 +03003446 if (changed & BSS_CHANGED_IBSS) {
3447 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3448 bss_conf->ibss_joined);
3449
3450 if (bss_conf->ibss_joined) {
3451 u32 rates = bss_conf->basic_rates;
3452 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3453 rates);
3454 wl->basic_rate = wl1271_tx_min_rate_get(wl);
3455
3456 /* by default, use 11b rates */
3457 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3458 ret = wl1271_acx_sta_rate_policies(wl);
3459 if (ret < 0)
3460 goto out;
3461 }
3462 }
3463
Arik Nemtsove78a2872010-10-16 19:07:21 +02003464 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3465 if (ret < 0)
3466 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003467
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003468 if (changed & BSS_CHANGED_ARP_FILTER) {
3469 __be32 addr = bss_conf->arp_addr_list[0];
3470 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3471
Eliad Pellerc5312772010-12-09 11:31:27 +02003472 if (bss_conf->arp_addr_cnt == 1 &&
3473 bss_conf->arp_filter_enabled) {
3474 /*
3475 * The template should have been configured only upon
3476 * association. however, it seems that the correct ip
3477 * isn't being set (when sending), so we have to
3478 * reconfigure the template upon every ip change.
3479 */
3480 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3481 if (ret < 0) {
3482 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003483 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003484 }
3485
3486 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003487 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003488 addr);
3489 } else
3490 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003491
3492 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003493 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003494 }
3495
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003496 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003497 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003498 if (ret < 0) {
3499 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003500 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003501 }
Eliad Peller251c1772011-08-14 13:17:17 +03003502
3503 /* ROC until connected (after EAPOL exchange) */
3504 if (!is_ibss) {
3505 ret = wl12xx_roc(wl, wl->role_id);
3506 if (ret < 0)
3507 goto out;
3508
3509 wl1271_check_operstate(wl,
3510 ieee80211_get_operstate(vif));
3511 }
3512 /*
3513 * stop device role if started (we might already be in
3514 * STA role). TODO: make it better.
3515 */
3516 if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3517 ret = wl12xx_croc(wl, wl->dev_role_id);
3518 if (ret < 0)
3519 goto out;
3520
3521 ret = wl12xx_cmd_role_stop_dev(wl);
3522 if (ret < 0)
3523 goto out;
3524 }
Eliad Peller05dba352011-08-23 16:37:01 +03003525
3526 /* If we want to go in PSM but we're not there yet */
3527 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3528 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
3529 enum wl1271_cmd_ps_mode mode;
3530
3531 mode = STATION_POWER_SAVE_MODE;
3532 ret = wl1271_ps_set_mode(wl, mode,
3533 wl->basic_rate,
3534 true);
3535 if (ret < 0)
3536 goto out;
3537 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003538 }
3539
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003540 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003541 if (sta_exists) {
3542 if ((changed & BSS_CHANGED_HT) &&
3543 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003544 ret = wl1271_acx_set_ht_capabilities(wl,
3545 &sta_ht_cap,
3546 true,
3547 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003548 if (ret < 0) {
3549 wl1271_warning("Set ht cap true failed %d",
3550 ret);
3551 goto out;
3552 }
3553 }
3554 /* handle new association without HT and disassociation */
3555 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003556 ret = wl1271_acx_set_ht_capabilities(wl,
3557 &sta_ht_cap,
3558 false,
3559 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003560 if (ret < 0) {
3561 wl1271_warning("Set ht cap false failed %d",
3562 ret);
3563 goto out;
3564 }
3565 }
3566 }
3567
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003568 /* Handle HT information change. Done after join. */
3569 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003570 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
3571 ret = wl1271_acx_set_ht_information(wl,
3572 bss_conf->ht_operation_mode);
3573 if (ret < 0) {
3574 wl1271_warning("Set ht information failed %d", ret);
3575 goto out;
3576 }
3577 }
3578
Arik Nemtsove78a2872010-10-16 19:07:21 +02003579out:
3580 return;
3581}
3582
3583static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3584 struct ieee80211_vif *vif,
3585 struct ieee80211_bss_conf *bss_conf,
3586 u32 changed)
3587{
3588 struct wl1271 *wl = hw->priv;
3589 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3590 int ret;
3591
3592 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3593 (int)changed);
3594
3595 mutex_lock(&wl->mutex);
3596
3597 if (unlikely(wl->state == WL1271_STATE_OFF))
3598 goto out;
3599
Ido Yariva6208652011-03-01 15:14:41 +02003600 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003601 if (ret < 0)
3602 goto out;
3603
3604 if (is_ap)
3605 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3606 else
3607 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3608
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003609 wl1271_ps_elp_sleep(wl);
3610
3611out:
3612 mutex_unlock(&wl->mutex);
3613}
3614
Kalle Valoc6999d82010-02-18 13:25:41 +02003615static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3616 const struct ieee80211_tx_queue_params *params)
3617{
3618 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003619 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003620 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003621
3622 mutex_lock(&wl->mutex);
3623
3624 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3625
Kalle Valo4695dc92010-03-18 12:26:38 +02003626 if (params->uapsd)
3627 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3628 else
3629 ps_scheme = CONF_PS_SCHEME_LEGACY;
3630
Arik Nemtsov488fc542010-10-16 20:33:45 +02003631 if (wl->state == WL1271_STATE_OFF) {
3632 /*
3633 * If the state is off, the parameters will be recorded and
3634 * configured on init. This happens in AP-mode.
3635 */
3636 struct conf_tx_ac_category *conf_ac =
3637 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3638 struct conf_tx_tid *conf_tid =
3639 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3640
3641 conf_ac->ac = wl1271_tx_get_queue(queue);
3642 conf_ac->cw_min = (u8)params->cw_min;
3643 conf_ac->cw_max = params->cw_max;
3644 conf_ac->aifsn = params->aifs;
3645 conf_ac->tx_op_limit = params->txop << 5;
3646
3647 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3648 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3649 conf_tid->tsid = wl1271_tx_get_queue(queue);
3650 conf_tid->ps_scheme = ps_scheme;
3651 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3652 conf_tid->apsd_conf[0] = 0;
3653 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003654 goto out;
3655 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003656
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003657 ret = wl1271_ps_elp_wakeup(wl);
3658 if (ret < 0)
3659 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003660
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003661 /*
3662 * the txop is confed in units of 32us by the mac80211,
3663 * we need us
3664 */
3665 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3666 params->cw_min, params->cw_max,
3667 params->aifs, params->txop << 5);
3668 if (ret < 0)
3669 goto out_sleep;
3670
3671 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3672 CONF_CHANNEL_TYPE_EDCF,
3673 wl1271_tx_get_queue(queue),
3674 ps_scheme, CONF_ACK_POLICY_LEGACY,
3675 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003676
3677out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003678 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003679
3680out:
3681 mutex_unlock(&wl->mutex);
3682
3683 return ret;
3684}
3685
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003686static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3687{
3688
3689 struct wl1271 *wl = hw->priv;
3690 u64 mactime = ULLONG_MAX;
3691 int ret;
3692
3693 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3694
3695 mutex_lock(&wl->mutex);
3696
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003697 if (unlikely(wl->state == WL1271_STATE_OFF))
3698 goto out;
3699
Ido Yariva6208652011-03-01 15:14:41 +02003700 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003701 if (ret < 0)
3702 goto out;
3703
3704 ret = wl1271_acx_tsf_info(wl, &mactime);
3705 if (ret < 0)
3706 goto out_sleep;
3707
3708out_sleep:
3709 wl1271_ps_elp_sleep(wl);
3710
3711out:
3712 mutex_unlock(&wl->mutex);
3713 return mactime;
3714}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003715
John W. Linvilleece550d2010-07-28 16:41:06 -04003716static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3717 struct survey_info *survey)
3718{
3719 struct wl1271 *wl = hw->priv;
3720 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003721
John W. Linvilleece550d2010-07-28 16:41:06 -04003722 if (idx != 0)
3723 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003724
John W. Linvilleece550d2010-07-28 16:41:06 -04003725 survey->channel = conf->channel;
3726 survey->filled = SURVEY_INFO_NOISE_DBM;
3727 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003728
John W. Linvilleece550d2010-07-28 16:41:06 -04003729 return 0;
3730}
3731
Arik Nemtsov409622e2011-02-23 00:22:29 +02003732static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003733 struct ieee80211_sta *sta,
3734 u8 *hlid)
3735{
3736 struct wl1271_station *wl_sta;
3737 int id;
3738
3739 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3740 if (id >= AP_MAX_STATIONS) {
3741 wl1271_warning("could not allocate HLID - too much stations");
3742 return -EBUSY;
3743 }
3744
3745 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsov04216da2011-08-14 13:17:38 +03003746 set_bit(id, wl->ap_hlid_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003747 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3748 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003749 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003750 return 0;
3751}
3752
Arik Nemtsov409622e2011-02-23 00:22:29 +02003753static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003754{
3755 int id = hlid - WL1271_AP_STA_HLID_START;
3756
Arik Nemtsov409622e2011-02-23 00:22:29 +02003757 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3758 return;
3759
Arik Nemtsov04216da2011-08-14 13:17:38 +03003760 clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003761 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003762 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003763 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003764 __clear_bit(hlid, &wl->ap_ps_map);
3765 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003766}
3767
3768static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3769 struct ieee80211_vif *vif,
3770 struct ieee80211_sta *sta)
3771{
3772 struct wl1271 *wl = hw->priv;
3773 int ret = 0;
3774 u8 hlid;
3775
3776 mutex_lock(&wl->mutex);
3777
3778 if (unlikely(wl->state == WL1271_STATE_OFF))
3779 goto out;
3780
3781 if (wl->bss_type != BSS_TYPE_AP_BSS)
3782 goto out;
3783
3784 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3785
Arik Nemtsov409622e2011-02-23 00:22:29 +02003786 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003787 if (ret < 0)
3788 goto out;
3789
Ido Yariva6208652011-03-01 15:14:41 +02003790 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003791 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003792 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003793
Eliad Pellerc690ec82011-08-14 13:17:07 +03003794 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003795 if (ret < 0)
3796 goto out_sleep;
3797
Eliad Pellerb67476e2011-08-14 13:17:23 +03003798 ret = wl12xx_cmd_set_peer_state(wl, hlid);
3799 if (ret < 0)
3800 goto out_sleep;
3801
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003802 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
3803 if (ret < 0)
3804 goto out_sleep;
3805
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003806out_sleep:
3807 wl1271_ps_elp_sleep(wl);
3808
Arik Nemtsov409622e2011-02-23 00:22:29 +02003809out_free_sta:
3810 if (ret < 0)
3811 wl1271_free_sta(wl, hlid);
3812
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003813out:
3814 mutex_unlock(&wl->mutex);
3815 return ret;
3816}
3817
3818static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3819 struct ieee80211_vif *vif,
3820 struct ieee80211_sta *sta)
3821{
3822 struct wl1271 *wl = hw->priv;
3823 struct wl1271_station *wl_sta;
3824 int ret = 0, id;
3825
3826 mutex_lock(&wl->mutex);
3827
3828 if (unlikely(wl->state == WL1271_STATE_OFF))
3829 goto out;
3830
3831 if (wl->bss_type != BSS_TYPE_AP_BSS)
3832 goto out;
3833
3834 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3835
3836 wl_sta = (struct wl1271_station *)sta->drv_priv;
3837 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3838 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3839 goto out;
3840
Ido Yariva6208652011-03-01 15:14:41 +02003841 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003842 if (ret < 0)
3843 goto out;
3844
Eliad Pellerc690ec82011-08-14 13:17:07 +03003845 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003846 if (ret < 0)
3847 goto out_sleep;
3848
Arik Nemtsov409622e2011-02-23 00:22:29 +02003849 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003850
3851out_sleep:
3852 wl1271_ps_elp_sleep(wl);
3853
3854out:
3855 mutex_unlock(&wl->mutex);
3856 return ret;
3857}
3858
Luciano Coelho4623ec72011-03-21 19:26:41 +02003859static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3860 struct ieee80211_vif *vif,
3861 enum ieee80211_ampdu_mlme_action action,
3862 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3863 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003864{
3865 struct wl1271 *wl = hw->priv;
3866 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003867 u8 hlid, *ba_bitmap;
3868
3869 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
3870 tid);
3871
3872 /* sanity check - the fields in FW are only 8bits wide */
3873 if (WARN_ON(tid > 0xFF))
3874 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003875
3876 mutex_lock(&wl->mutex);
3877
3878 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3879 ret = -EAGAIN;
3880 goto out;
3881 }
3882
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003883 if (wl->bss_type == BSS_TYPE_STA_BSS) {
3884 hlid = wl->sta_hlid;
3885 ba_bitmap = &wl->ba_rx_bitmap;
3886 } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
3887 struct wl1271_station *wl_sta;
3888
3889 wl_sta = (struct wl1271_station *)sta->drv_priv;
3890 hlid = wl_sta->hlid;
3891 ba_bitmap = &wl->links[hlid].ba_bitmap;
3892 } else {
3893 ret = -EINVAL;
3894 goto out;
3895 }
3896
Ido Yariva6208652011-03-01 15:14:41 +02003897 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003898 if (ret < 0)
3899 goto out;
3900
Shahar Levi70559a02011-05-22 16:10:22 +03003901 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3902 tid, action);
3903
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003904 switch (action) {
3905 case IEEE80211_AMPDU_RX_START:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003906 if (!wl->ba_support || !wl->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003907 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003908 break;
3909 }
3910
3911 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
3912 ret = -EBUSY;
3913 wl1271_error("exceeded max RX BA sessions");
3914 break;
3915 }
3916
3917 if (*ba_bitmap & BIT(tid)) {
3918 ret = -EINVAL;
3919 wl1271_error("cannot enable RX BA session on active "
3920 "tid: %d", tid);
3921 break;
3922 }
3923
3924 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
3925 hlid);
3926 if (!ret) {
3927 *ba_bitmap |= BIT(tid);
3928 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003929 }
3930 break;
3931
3932 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003933 if (!(*ba_bitmap & BIT(tid))) {
3934 ret = -EINVAL;
3935 wl1271_error("no active RX BA session on tid: %d",
3936 tid);
3937 break;
3938 }
3939
3940 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
3941 hlid);
3942 if (!ret) {
3943 *ba_bitmap &= ~BIT(tid);
3944 wl->ba_rx_session_count--;
3945 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003946 break;
3947
3948 /*
3949 * The BA initiator session management in FW independently.
3950 * Falling break here on purpose for all TX APDU commands.
3951 */
3952 case IEEE80211_AMPDU_TX_START:
3953 case IEEE80211_AMPDU_TX_STOP:
3954 case IEEE80211_AMPDU_TX_OPERATIONAL:
3955 ret = -EINVAL;
3956 break;
3957
3958 default:
3959 wl1271_error("Incorrect ampdu action id=%x\n", action);
3960 ret = -EINVAL;
3961 }
3962
3963 wl1271_ps_elp_sleep(wl);
3964
3965out:
3966 mutex_unlock(&wl->mutex);
3967
3968 return ret;
3969}
3970
Arik Nemtsov33437892011-04-26 23:35:39 +03003971static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3972{
3973 struct wl1271 *wl = hw->priv;
3974 bool ret = false;
3975
3976 mutex_lock(&wl->mutex);
3977
3978 if (unlikely(wl->state == WL1271_STATE_OFF))
3979 goto out;
3980
3981 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03003982 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03003983
3984 /* the above is appropriate for STA mode for PS purposes */
3985 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3986
3987out:
3988 mutex_unlock(&wl->mutex);
3989
3990 return ret;
3991}
3992
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003993/* can't be const, mac80211 writes to this */
3994static struct ieee80211_rate wl1271_rates[] = {
3995 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003996 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3997 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003998 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003999 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4000 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004001 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4002 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004003 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4004 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004005 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4006 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004007 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4008 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004009 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4010 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004011 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4012 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004013 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004014 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4015 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004016 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004017 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4018 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004019 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004020 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4021 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004022 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004023 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4024 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004025 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004026 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4027 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004028 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004029 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4030 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004031 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004032 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4033 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004034};
4035
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004036/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004037static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004038 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004039 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004040 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4041 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4042 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004043 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004044 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4045 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4046 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004047 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004048 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4049 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4050 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004051 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004052};
4053
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004054/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004055static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004056 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004057 7, /* CONF_HW_RXTX_RATE_MCS7 */
4058 6, /* CONF_HW_RXTX_RATE_MCS6 */
4059 5, /* CONF_HW_RXTX_RATE_MCS5 */
4060 4, /* CONF_HW_RXTX_RATE_MCS4 */
4061 3, /* CONF_HW_RXTX_RATE_MCS3 */
4062 2, /* CONF_HW_RXTX_RATE_MCS2 */
4063 1, /* CONF_HW_RXTX_RATE_MCS1 */
4064 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004065
4066 11, /* CONF_HW_RXTX_RATE_54 */
4067 10, /* CONF_HW_RXTX_RATE_48 */
4068 9, /* CONF_HW_RXTX_RATE_36 */
4069 8, /* CONF_HW_RXTX_RATE_24 */
4070
4071 /* TI-specific rate */
4072 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4073
4074 7, /* CONF_HW_RXTX_RATE_18 */
4075 6, /* CONF_HW_RXTX_RATE_12 */
4076 3, /* CONF_HW_RXTX_RATE_11 */
4077 5, /* CONF_HW_RXTX_RATE_9 */
4078 4, /* CONF_HW_RXTX_RATE_6 */
4079 2, /* CONF_HW_RXTX_RATE_5_5 */
4080 1, /* CONF_HW_RXTX_RATE_2 */
4081 0 /* CONF_HW_RXTX_RATE_1 */
4082};
4083
Shahar Levie8b03a22010-10-13 16:09:39 +02004084/* 11n STA capabilities */
4085#define HW_RX_HIGHEST_RATE 72
4086
Shahar Levi00d20102010-11-08 11:20:10 +00004087#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004088 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4089 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004090 .ht_supported = true, \
4091 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4092 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4093 .mcs = { \
4094 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4095 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4096 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4097 }, \
4098}
4099
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004100/* can't be const, mac80211 writes to this */
4101static struct ieee80211_supported_band wl1271_band_2ghz = {
4102 .channels = wl1271_channels,
4103 .n_channels = ARRAY_SIZE(wl1271_channels),
4104 .bitrates = wl1271_rates,
4105 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004106 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004107};
4108
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004109/* 5 GHz data rates for WL1273 */
4110static struct ieee80211_rate wl1271_rates_5ghz[] = {
4111 { .bitrate = 60,
4112 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4113 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4114 { .bitrate = 90,
4115 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4116 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4117 { .bitrate = 120,
4118 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4119 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4120 { .bitrate = 180,
4121 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4122 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4123 { .bitrate = 240,
4124 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4125 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4126 { .bitrate = 360,
4127 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4128 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4129 { .bitrate = 480,
4130 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4131 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4132 { .bitrate = 540,
4133 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4134 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4135};
4136
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004137/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004138static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004139 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4140 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4141 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4142 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4143 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4144 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4145 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4146 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4147 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4148 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4149 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4150 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4151 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4152 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4153 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4154 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4155 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4156 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4157 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4158 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4159 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4160 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4161 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4162 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4163 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4164 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4165 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4166 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4167 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4168 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4169 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4170 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4171 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4172 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004173};
4174
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004175/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004176static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004177 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004178 7, /* CONF_HW_RXTX_RATE_MCS7 */
4179 6, /* CONF_HW_RXTX_RATE_MCS6 */
4180 5, /* CONF_HW_RXTX_RATE_MCS5 */
4181 4, /* CONF_HW_RXTX_RATE_MCS4 */
4182 3, /* CONF_HW_RXTX_RATE_MCS3 */
4183 2, /* CONF_HW_RXTX_RATE_MCS2 */
4184 1, /* CONF_HW_RXTX_RATE_MCS1 */
4185 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004186
4187 7, /* CONF_HW_RXTX_RATE_54 */
4188 6, /* CONF_HW_RXTX_RATE_48 */
4189 5, /* CONF_HW_RXTX_RATE_36 */
4190 4, /* CONF_HW_RXTX_RATE_24 */
4191
4192 /* TI-specific rate */
4193 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4194
4195 3, /* CONF_HW_RXTX_RATE_18 */
4196 2, /* CONF_HW_RXTX_RATE_12 */
4197 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4198 1, /* CONF_HW_RXTX_RATE_9 */
4199 0, /* CONF_HW_RXTX_RATE_6 */
4200 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4201 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4202 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4203};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004204
4205static struct ieee80211_supported_band wl1271_band_5ghz = {
4206 .channels = wl1271_channels_5ghz,
4207 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4208 .bitrates = wl1271_rates_5ghz,
4209 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004210 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004211};
4212
Tobias Klausera0ea9492010-05-20 10:38:11 +02004213static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004214 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4215 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4216};
4217
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004218static const struct ieee80211_ops wl1271_ops = {
4219 .start = wl1271_op_start,
4220 .stop = wl1271_op_stop,
4221 .add_interface = wl1271_op_add_interface,
4222 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004223#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004224 .suspend = wl1271_op_suspend,
4225 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004226#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004227 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004228 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004229 .configure_filter = wl1271_op_configure_filter,
4230 .tx = wl1271_op_tx,
4231 .set_key = wl1271_op_set_key,
4232 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004233 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004234 .sched_scan_start = wl1271_op_sched_scan_start,
4235 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004236 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004237 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004238 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004239 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004240 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004241 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004242 .sta_add = wl1271_op_sta_add,
4243 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004244 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004245 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02004246 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004247};
4248
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004249
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004250u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004251{
4252 u8 idx;
4253
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004254 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004255
4256 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4257 wl1271_error("Illegal RX rate from HW: %d", rate);
4258 return 0;
4259 }
4260
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004261 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004262 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4263 wl1271_error("Unsupported RX rate from HW: %d", rate);
4264 return 0;
4265 }
4266
4267 return idx;
4268}
4269
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004270static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4271 struct device_attribute *attr,
4272 char *buf)
4273{
4274 struct wl1271 *wl = dev_get_drvdata(dev);
4275 ssize_t len;
4276
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004277 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004278
4279 mutex_lock(&wl->mutex);
4280 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4281 wl->sg_enabled);
4282 mutex_unlock(&wl->mutex);
4283
4284 return len;
4285
4286}
4287
4288static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4289 struct device_attribute *attr,
4290 const char *buf, size_t count)
4291{
4292 struct wl1271 *wl = dev_get_drvdata(dev);
4293 unsigned long res;
4294 int ret;
4295
Luciano Coelho6277ed62011-04-01 17:49:54 +03004296 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004297 if (ret < 0) {
4298 wl1271_warning("incorrect value written to bt_coex_mode");
4299 return count;
4300 }
4301
4302 mutex_lock(&wl->mutex);
4303
4304 res = !!res;
4305
4306 if (res == wl->sg_enabled)
4307 goto out;
4308
4309 wl->sg_enabled = res;
4310
4311 if (wl->state == WL1271_STATE_OFF)
4312 goto out;
4313
Ido Yariva6208652011-03-01 15:14:41 +02004314 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004315 if (ret < 0)
4316 goto out;
4317
4318 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4319 wl1271_ps_elp_sleep(wl);
4320
4321 out:
4322 mutex_unlock(&wl->mutex);
4323 return count;
4324}
4325
4326static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4327 wl1271_sysfs_show_bt_coex_state,
4328 wl1271_sysfs_store_bt_coex_state);
4329
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004330static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4331 struct device_attribute *attr,
4332 char *buf)
4333{
4334 struct wl1271 *wl = dev_get_drvdata(dev);
4335 ssize_t len;
4336
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004337 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004338
4339 mutex_lock(&wl->mutex);
4340 if (wl->hw_pg_ver >= 0)
4341 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4342 else
4343 len = snprintf(buf, len, "n/a\n");
4344 mutex_unlock(&wl->mutex);
4345
4346 return len;
4347}
4348
Gery Kahn6f07b722011-07-18 14:21:49 +03004349static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004350 wl1271_sysfs_show_hw_pg_ver, NULL);
4351
Ido Yariv95dac04f2011-06-06 14:57:06 +03004352static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4353 struct bin_attribute *bin_attr,
4354 char *buffer, loff_t pos, size_t count)
4355{
4356 struct device *dev = container_of(kobj, struct device, kobj);
4357 struct wl1271 *wl = dev_get_drvdata(dev);
4358 ssize_t len;
4359 int ret;
4360
4361 ret = mutex_lock_interruptible(&wl->mutex);
4362 if (ret < 0)
4363 return -ERESTARTSYS;
4364
4365 /* Let only one thread read the log at a time, blocking others */
4366 while (wl->fwlog_size == 0) {
4367 DEFINE_WAIT(wait);
4368
4369 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4370 &wait,
4371 TASK_INTERRUPTIBLE);
4372
4373 if (wl->fwlog_size != 0) {
4374 finish_wait(&wl->fwlog_waitq, &wait);
4375 break;
4376 }
4377
4378 mutex_unlock(&wl->mutex);
4379
4380 schedule();
4381 finish_wait(&wl->fwlog_waitq, &wait);
4382
4383 if (signal_pending(current))
4384 return -ERESTARTSYS;
4385
4386 ret = mutex_lock_interruptible(&wl->mutex);
4387 if (ret < 0)
4388 return -ERESTARTSYS;
4389 }
4390
4391 /* Check if the fwlog is still valid */
4392 if (wl->fwlog_size < 0) {
4393 mutex_unlock(&wl->mutex);
4394 return 0;
4395 }
4396
4397 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4398 len = min(count, (size_t)wl->fwlog_size);
4399 wl->fwlog_size -= len;
4400 memcpy(buffer, wl->fwlog, len);
4401
4402 /* Make room for new messages */
4403 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4404
4405 mutex_unlock(&wl->mutex);
4406
4407 return len;
4408}
4409
4410static struct bin_attribute fwlog_attr = {
4411 .attr = {.name = "fwlog", .mode = S_IRUSR},
4412 .read = wl1271_sysfs_read_fwlog,
4413};
4414
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004415int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004416{
4417 int ret;
4418
4419 if (wl->mac80211_registered)
4420 return 0;
4421
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004422 ret = wl1271_fetch_nvs(wl);
4423 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004424 /* NOTE: The wl->nvs->nvs element must be first, in
4425 * order to simplify the casting, we assume it is at
4426 * the beginning of the wl->nvs structure.
4427 */
4428 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004429
4430 wl->mac_addr[0] = nvs_ptr[11];
4431 wl->mac_addr[1] = nvs_ptr[10];
4432 wl->mac_addr[2] = nvs_ptr[6];
4433 wl->mac_addr[3] = nvs_ptr[5];
4434 wl->mac_addr[4] = nvs_ptr[4];
4435 wl->mac_addr[5] = nvs_ptr[3];
4436 }
4437
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004438 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4439
4440 ret = ieee80211_register_hw(wl->hw);
4441 if (ret < 0) {
4442 wl1271_error("unable to register mac80211 hw: %d", ret);
4443 return ret;
4444 }
4445
4446 wl->mac80211_registered = true;
4447
Eliad Pellerd60080a2010-11-24 12:53:16 +02004448 wl1271_debugfs_init(wl);
4449
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004450 register_netdevice_notifier(&wl1271_dev_notifier);
4451
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004452 wl1271_notice("loaded");
4453
4454 return 0;
4455}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004456EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004457
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004458void wl1271_unregister_hw(struct wl1271 *wl)
4459{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004460 if (wl->state == WL1271_STATE_PLT)
4461 __wl1271_plt_stop(wl);
4462
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004463 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004464 ieee80211_unregister_hw(wl->hw);
4465 wl->mac80211_registered = false;
4466
4467}
4468EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4469
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004470int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004471{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004472 static const u32 cipher_suites[] = {
4473 WLAN_CIPHER_SUITE_WEP40,
4474 WLAN_CIPHER_SUITE_WEP104,
4475 WLAN_CIPHER_SUITE_TKIP,
4476 WLAN_CIPHER_SUITE_CCMP,
4477 WL1271_CIPHER_SUITE_GEM,
4478 };
4479
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004480 /* The tx descriptor buffer and the TKIP space. */
4481 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4482 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004483
4484 /* unit us */
4485 /* FIXME: find a proper value */
4486 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004487 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004488
4489 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004490 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004491 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004492 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004493 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004494 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004495 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004496 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004497 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02004498 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004499
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004500 wl->hw->wiphy->cipher_suites = cipher_suites;
4501 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4502
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004503 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02004504 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004505 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004506 wl->hw->wiphy->max_sched_scan_ssids = 16;
4507 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004508 /*
4509 * Maximum length of elements in scanning probe request templates
4510 * should be the maximum length possible for a template, without
4511 * the IEEE80211 header of the template
4512 */
Eliad Peller154037d2011-08-14 13:17:12 +03004513 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004514 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004515
Eliad Peller1ec23f72011-08-25 14:26:54 +03004516 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4517
Luciano Coelho4a31c112011-03-21 23:16:14 +02004518 /* make sure all our channels fit in the scanned_ch bitmask */
4519 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4520 ARRAY_SIZE(wl1271_channels_5ghz) >
4521 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004522 /*
4523 * We keep local copies of the band structs because we need to
4524 * modify them on a per-device basis.
4525 */
4526 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4527 sizeof(wl1271_band_2ghz));
4528 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4529 sizeof(wl1271_band_5ghz));
4530
4531 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4532 &wl->bands[IEEE80211_BAND_2GHZ];
4533 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4534 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004535
Kalle Valo12bd8942010-03-18 12:26:33 +02004536 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004537 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004538
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004539 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4540
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004541 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004542
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004543 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4544
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004545 wl->hw->max_rx_aggregation_subframes = 8;
4546
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004547 return 0;
4548}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004549EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004550
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004551#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004552
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004553struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004554{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004555 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004556 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004557 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004558 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004559 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004560
4561 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4562 if (!hw) {
4563 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004564 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004565 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004566 }
4567
Julia Lawall929ebd32010-05-15 23:16:39 +02004568 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004569 if (!plat_dev) {
4570 wl1271_error("could not allocate platform_device");
4571 ret = -ENOMEM;
4572 goto err_plat_alloc;
4573 }
4574
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004575 wl = hw->priv;
4576 memset(wl, 0, sizeof(*wl));
4577
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004578 INIT_LIST_HEAD(&wl->list);
4579
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004580 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004581 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004582
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004583 for (i = 0; i < NUM_TX_QUEUES; i++)
4584 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004585
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004586 for (i = 0; i < NUM_TX_QUEUES; i++)
4587 for (j = 0; j < AP_MAX_LINKS; j++)
4588 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4589
Ido Yariva6208652011-03-01 15:14:41 +02004590 skb_queue_head_init(&wl->deferred_rx_queue);
4591 skb_queue_head_init(&wl->deferred_tx_queue);
4592
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004593 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004594 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004595 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004596 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4597 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4598 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004599 INIT_WORK(&wl->rx_streaming_enable_work,
4600 wl1271_rx_streaming_enable_work);
4601 INIT_WORK(&wl->rx_streaming_disable_work,
4602 wl1271_rx_streaming_disable_work);
4603
Eliad Peller92ef8962011-06-07 12:50:46 +03004604 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4605 if (!wl->freezable_wq) {
4606 ret = -ENOMEM;
4607 goto err_hw;
4608 }
4609
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004610 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004611 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004612 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004613 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004614 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004615 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004616 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004617 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004618 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004619 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004620 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004621 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004622 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004623 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004624 wl->bss_type = MAX_BSS_TYPE;
4625 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004626 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004627 wl->ap_ps_map = 0;
4628 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004629 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004630 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004631 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004632 wl->tx_security_seq = 0;
4633 wl->tx_security_last_seq_lsb = 0;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03004634 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Peller7f0979882011-08-14 13:17:06 +03004635 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004636 wl->system_hlid = WL12XX_SYSTEM_HLID;
Eliad Peller7f0979882011-08-14 13:17:06 +03004637 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004638 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4639 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsov712e9bf2011-08-14 13:17:20 +03004640 wl->session_counter = 0;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03004641 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
4642 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004643 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4644 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004645 wl->fwlog_size = 0;
4646 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004647
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004648 /* The system link is always allocated */
4649 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4650
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004651 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004652 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004653 wl->tx_frames[i] = NULL;
4654
4655 spin_lock_init(&wl->wl_lock);
4656
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004657 wl->state = WL1271_STATE_OFF;
4658 mutex_init(&wl->mutex);
4659
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004660 /* Apply default driver configuration. */
4661 wl1271_conf_init(wl);
4662
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004663 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4664 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4665 if (!wl->aggr_buf) {
4666 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004667 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004668 }
4669
Ido Yariv990f5de2011-03-31 10:06:59 +02004670 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4671 if (!wl->dummy_packet) {
4672 ret = -ENOMEM;
4673 goto err_aggr;
4674 }
4675
Ido Yariv95dac04f2011-06-06 14:57:06 +03004676 /* Allocate one page for the FW log */
4677 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4678 if (!wl->fwlog) {
4679 ret = -ENOMEM;
4680 goto err_dummy_packet;
4681 }
4682
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004683 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004684 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004685 if (ret) {
4686 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004687 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004688 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004689 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004690
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004691 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004692 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004693 if (ret < 0) {
4694 wl1271_error("failed to create sysfs file bt_coex_state");
4695 goto err_platform;
4696 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004697
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004698 /* Create sysfs file to get HW PG version */
4699 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4700 if (ret < 0) {
4701 wl1271_error("failed to create sysfs file hw_pg_ver");
4702 goto err_bt_coex_state;
4703 }
4704
Ido Yariv95dac04f2011-06-06 14:57:06 +03004705 /* Create sysfs file for the FW log */
4706 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4707 if (ret < 0) {
4708 wl1271_error("failed to create sysfs file fwlog");
4709 goto err_hw_pg_ver;
4710 }
4711
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004712 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004713
Ido Yariv95dac04f2011-06-06 14:57:06 +03004714err_hw_pg_ver:
4715 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4716
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004717err_bt_coex_state:
4718 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4719
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004720err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004721 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004722
Ido Yariv95dac04f2011-06-06 14:57:06 +03004723err_fwlog:
4724 free_page((unsigned long)wl->fwlog);
4725
Ido Yariv990f5de2011-03-31 10:06:59 +02004726err_dummy_packet:
4727 dev_kfree_skb(wl->dummy_packet);
4728
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004729err_aggr:
4730 free_pages((unsigned long)wl->aggr_buf, order);
4731
Eliad Peller92ef8962011-06-07 12:50:46 +03004732err_wq:
4733 destroy_workqueue(wl->freezable_wq);
4734
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004735err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004736 wl1271_debugfs_exit(wl);
4737 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004738
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004739err_plat_alloc:
4740 ieee80211_free_hw(hw);
4741
4742err_hw_alloc:
4743
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004744 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004745}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004746EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004747
4748int wl1271_free_hw(struct wl1271 *wl)
4749{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004750 /* Unblock any fwlog readers */
4751 mutex_lock(&wl->mutex);
4752 wl->fwlog_size = -1;
4753 wake_up_interruptible_all(&wl->fwlog_waitq);
4754 mutex_unlock(&wl->mutex);
4755
4756 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004757
4758 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4759
4760 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004761 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004762 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02004763 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004764 free_pages((unsigned long)wl->aggr_buf,
4765 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004766 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004767
4768 wl1271_debugfs_exit(wl);
4769
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004770 vfree(wl->fw);
4771 wl->fw = NULL;
4772 kfree(wl->nvs);
4773 wl->nvs = NULL;
4774
4775 kfree(wl->fw_status);
4776 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03004777 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004778
4779 ieee80211_free_hw(wl->hw);
4780
4781 return 0;
4782}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004783EXPORT_SYMBOL_GPL(wl1271_free_hw);
4784
Guy Eilam491bbd62011-01-12 10:33:29 +01004785u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004786EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004787module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004788MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4789
Ido Yariv95dac04f2011-06-06 14:57:06 +03004790module_param_named(fwlog, fwlog_param, charp, 0);
4791MODULE_PARM_DESC(keymap,
4792 "FW logger options: continuous, ondemand, dbgpins or disable");
4793
Eliad Peller2a5bff02011-08-25 18:10:59 +03004794module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
4795MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
4796
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004797MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004798MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004799MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");