blob: f76be5ad8ab093568dd3c7e7027d8a4bcb5420d9 [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>
Felipe Balbia390e852011-10-06 10:07:44 +030035#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "wl12xx.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030038#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030039#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000040#include "reg.h"
41#include "io.h"
42#include "event.h"
43#include "tx.h"
44#include "rx.h"
45#include "ps.h"
46#include "init.h"
47#include "debugfs.h"
48#include "cmd.h"
49#include "boot.h"
50#include "testmode.h"
51#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030052
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020053#define WL1271_BOOT_RETRIES 3
54
Juuso Oikarinen8a080482009-10-13 12:47:44 +030055static struct conf_drv_settings default_conf = {
56 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030057 .params = {
58 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
61 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
62 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
64 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
65 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
66 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
68 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
69 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
70 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
71 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
73 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
74 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
75 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
76 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
77 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
78 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
79 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
82 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
83 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
84 /* active scan params */
85 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
86 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
87 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
88 /* passive scan params */
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
91 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
92 /* passive scan in dual antenna params */
93 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
94 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
95 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
96 /* general params */
97 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
98 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
99 [CONF_SG_BEACON_MISS_PERCENT] = 60,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_RXT] = 1200,
102 [CONF_SG_TXT] = 1000,
103 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
104 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
105 [CONF_SG_HV3_MAX_SERVED] = 6,
106 [CONF_SG_PS_POLL_TIMEOUT] = 10,
107 [CONF_SG_UPSD_TIMEOUT] = 10,
108 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
109 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
110 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
111 /* AP params */
112 [CONF_AP_BEACON_MISS_TX] = 3,
113 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
114 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
115 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
116 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
117 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300118 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200119 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300120 },
121 .rx = {
122 .rx_msdu_life_time = 512000,
123 .packet_detection_threshold = 0,
124 .ps_poll_timeout = 15,
125 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300126 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200127 .rx_cca_threshold = 0,
128 .irq_blk_threshold = 0xFFFF,
129 .irq_pkt_threshold = 0,
130 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300131 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
132 },
133 .tx = {
134 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200135 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300136 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300137 .short_retry_limit = 10,
138 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200139 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300140 },
141 .ac_conf_count = 4,
142 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200143 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300144 .ac = CONF_TX_AC_BE,
145 .cw_min = 15,
146 .cw_max = 63,
147 .aifsn = 3,
148 .tx_op_limit = 0,
149 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200150 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300151 .ac = CONF_TX_AC_BK,
152 .cw_min = 15,
153 .cw_max = 63,
154 .aifsn = 7,
155 .tx_op_limit = 0,
156 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200157 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300158 .ac = CONF_TX_AC_VI,
159 .cw_min = 15,
160 .cw_max = 63,
161 .aifsn = CONF_TX_AIFS_PIFS,
162 .tx_op_limit = 3008,
163 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200164 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300165 .ac = CONF_TX_AC_VO,
166 .cw_min = 15,
167 .cw_max = 63,
168 .aifsn = CONF_TX_AIFS_PIFS,
169 .tx_op_limit = 1504,
170 },
171 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300172 .max_tx_retries = 100,
173 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300175 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200176 [CONF_TX_AC_BE] = {
177 .queue_id = CONF_TX_AC_BE,
178 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300179 .tsid = CONF_TX_AC_BE,
180 .ps_scheme = CONF_PS_SCHEME_LEGACY,
181 .ack_policy = CONF_ACK_POLICY_LEGACY,
182 .apsd_conf = {0, 0},
183 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200184 [CONF_TX_AC_BK] = {
185 .queue_id = CONF_TX_AC_BK,
186 .channel_type = CONF_CHANNEL_TYPE_EDCF,
187 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300188 .ps_scheme = CONF_PS_SCHEME_LEGACY,
189 .ack_policy = CONF_ACK_POLICY_LEGACY,
190 .apsd_conf = {0, 0},
191 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200192 [CONF_TX_AC_VI] = {
193 .queue_id = CONF_TX_AC_VI,
194 .channel_type = CONF_CHANNEL_TYPE_EDCF,
195 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .ps_scheme = CONF_PS_SCHEME_LEGACY,
197 .ack_policy = CONF_ACK_POLICY_LEGACY,
198 .apsd_conf = {0, 0},
199 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200200 [CONF_TX_AC_VO] = {
201 .queue_id = CONF_TX_AC_VO,
202 .channel_type = CONF_CHANNEL_TYPE_EDCF,
203 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300204 .ps_scheme = CONF_PS_SCHEME_LEGACY,
205 .ack_policy = CONF_ACK_POLICY_LEGACY,
206 .apsd_conf = {0, 0},
207 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300208 },
209 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200210 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300211 .tx_compl_threshold = 4,
212 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
213 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200214 .tmpl_short_retry_limit = 10,
215 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300216 },
217 .conn = {
218 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300219 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300221 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300222 .bcn_filt_ie = {
223 [0] = {
224 .ie = WLAN_EID_CHANNEL_SWITCH,
225 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300226 },
227 [1] = {
228 .ie = WLAN_EID_HT_INFORMATION,
229 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
230 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200232 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 .bss_lose_timeout = 100,
234 .beacon_rx_timeout = 10000,
235 .broadcast_timeout = 20000,
236 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300237 .ps_poll_threshold = 10,
238 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300239 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e02011-03-14 18:53:10 +0200240 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300241 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300242 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200243 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300244 .keep_alive_interval = 55000,
245 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300246 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200247 .itrim = {
248 .enable = false,
249 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200250 },
251 .pm_config = {
252 .host_clk_settling_time = 5000,
253 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 },
255 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300256 .trigger_pacing = 1,
257 .avg_weight_rssi_beacon = 20,
258 .avg_weight_rssi_data = 10,
259 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100260 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200261 },
262 .scan = {
263 .min_dwell_time_active = 7500,
264 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100265 .min_dwell_time_passive = 100000,
266 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200267 .num_probe_reqs = 2,
268 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300269 .sched_scan = {
270 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300271 .min_dwell_time_active = 30,
272 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300274 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300275 .num_probe_reqs = 2,
276 .rssi_threshold = -90,
277 .snr_threshold = 0,
278 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200279 .rf = {
280 .tx_per_channel_power_compensation_2 = {
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 },
283 .tx_per_channel_power_compensation_5 = {
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 },
288 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300290 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100291 .tx_ba_win_size = 64,
292 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300293 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100294 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200295 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200296 .num_stations = 1,
297 .ssid_profiles = 1,
298 .rx_block_num = 70,
299 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300300 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200301 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200302 .min_req_rx_blocks = 22,
303 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200304 },
305 .mem_wl128x = {
306 .num_stations = 1,
307 .ssid_profiles = 1,
308 .rx_block_num = 40,
309 .tx_min_block_num = 40,
310 .dynamic_memory = 1,
311 .min_req_tx_blocks = 45,
312 .min_req_rx_blocks = 22,
313 .tx_min = 27,
314 },
Shahar Leviff868432011-04-11 15:41:46 +0300315 .fm_coex = {
316 .enable = true,
317 .swallow_period = 5,
318 .n_divider_fref_set_1 = 0xff, /* default */
319 .n_divider_fref_set_2 = 12,
320 .m_divider_fref_set_1 = 148,
321 .m_divider_fref_set_2 = 0xffff, /* default */
322 .coex_pll_stabilization_time = 0xffffffff, /* default */
323 .ldo_stabilization_time = 0xffff, /* default */
324 .fm_disturbed_band_margin = 0xff, /* default */
325 .swallow_clk_diff = 0xff, /* default */
326 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300327 .rx_streaming = {
328 .duration = 150,
329 .queues = 0x1,
330 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300331 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300332 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300333 .fwlog = {
334 .mode = WL12XX_FWLOG_ON_DEMAND,
335 .mem_blocks = 2,
336 .severity = 0,
337 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
338 .output = WL12XX_FWLOG_OUTPUT_HOST,
339 .threshold = 0,
340 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300341 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300342 .rate = {
343 .rate_retry_score = 32000,
344 .per_add = 8192,
345 .per_th1 = 2048,
346 .per_th2 = 4096,
347 .max_per = 8100,
348 .inverse_curiosity_factor = 5,
349 .tx_fail_low_th = 4,
350 .tx_fail_high_th = 10,
351 .per_alpha_shift = 4,
352 .per_add_shift = 13,
353 .per_beta1_shift = 10,
354 .per_beta2_shift = 8,
355 .rate_check_up = 2,
356 .rate_check_down = 12,
357 .rate_retry_policy = {
358 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00,
361 },
362 },
Eliad Peller94877752011-08-28 15:11:56 +0300363 .hangover = {
364 .recover_time = 0,
365 .hangover_period = 20,
366 .dynamic_mode = 1,
367 .early_termination_mode = 1,
368 .max_period = 20,
369 .min_period = 1,
370 .increase_delta = 1,
371 .decrease_delta = 2,
372 .quiet_time = 4,
373 .increase_time = 1,
374 .window_size = 16,
375 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300376};
377
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300379static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300380
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300381static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200382 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300383 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200384static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200385static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200386
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200387static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300388static LIST_HEAD(wl_list);
389
Eliad Pellerba8447f2011-10-10 10:13:00 +0200390static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
391 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300392{
393 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200394
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300395 if (operstate != IF_OPER_UP)
396 return 0;
397
Eliad Peller8181aec2011-10-10 10:13:04 +0200398 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300399 return 0;
400
Eliad Peller154da672011-10-05 11:55:53 +0200401 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300402 if (ret < 0)
403 return ret;
404
Eliad Peller0603d892011-10-05 11:55:51 +0200405 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300406
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300407 wl1271_info("Association completed.");
408 return 0;
409}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300410static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
411 void *arg)
412{
413 struct net_device *dev = arg;
414 struct wireless_dev *wdev;
415 struct wiphy *wiphy;
416 struct ieee80211_hw *hw;
417 struct wl1271 *wl;
418 struct wl1271 *wl_temp;
Eliad Pellerba8447f2011-10-10 10:13:00 +0200419 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300420 int ret = 0;
421
422 /* Check that this notification is for us. */
423 if (what != NETDEV_CHANGE)
424 return NOTIFY_DONE;
425
426 wdev = dev->ieee80211_ptr;
427 if (wdev == NULL)
428 return NOTIFY_DONE;
429
430 wiphy = wdev->wiphy;
431 if (wiphy == NULL)
432 return NOTIFY_DONE;
433
434 hw = wiphy_priv(wiphy);
435 if (hw == NULL)
436 return NOTIFY_DONE;
437
438 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200439 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300440 list_for_each_entry(wl, &wl_list, list) {
441 if (wl == wl_temp)
442 break;
443 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200444 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300445 if (wl != wl_temp)
446 return NOTIFY_DONE;
447
448 mutex_lock(&wl->mutex);
449
450 if (wl->state == WL1271_STATE_OFF)
451 goto out;
452
Eliad Pellerba8447f2011-10-10 10:13:00 +0200453 wl12xx_for_each_wlvif_sta(wl, wlvif) {
454 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
455 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300456
Eliad Pellerba8447f2011-10-10 10:13:00 +0200457 ret = wl1271_ps_elp_wakeup(wl);
458 if (ret < 0)
459 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300460
Eliad Pellerba8447f2011-10-10 10:13:00 +0200461 wl1271_check_operstate(wl, wlvif, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300462
Eliad Pellerba8447f2011-10-10 10:13:00 +0200463 wl1271_ps_elp_sleep(wl);
464 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300465out:
466 mutex_unlock(&wl->mutex);
467
468 return NOTIFY_OK;
469}
470
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100471static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200472 struct regulatory_request *request)
473{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100474 struct ieee80211_supported_band *band;
475 struct ieee80211_channel *ch;
476 int i;
477
478 band = wiphy->bands[IEEE80211_BAND_5GHZ];
479 for (i = 0; i < band->n_channels; i++) {
480 ch = &band->channels[i];
481 if (ch->flags & IEEE80211_CHAN_DISABLED)
482 continue;
483
484 if (ch->flags & IEEE80211_CHAN_RADAR)
485 ch->flags |= IEEE80211_CHAN_NO_IBSS |
486 IEEE80211_CHAN_PASSIVE_SCAN;
487
488 }
489
490 return 0;
491}
492
Eliad Peller9eb599e2011-10-10 10:12:59 +0200493static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
494 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300495{
496 int ret = 0;
497
498 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200499 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300500 if (ret < 0)
501 goto out;
502
503 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200504 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300505 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200506 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300507out:
508 return ret;
509}
510
511/*
512 * this function is being called when the rx_streaming interval
513 * has beed changed or rx_streaming should be disabled
514 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200515int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300516{
517 int ret = 0;
518 int period = wl->conf.rx_streaming.interval;
519
520 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200521 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300522 goto out;
523
524 /* reconfigure/disable according to new streaming_period */
525 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200526 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300527 (wl->conf.rx_streaming.always ||
528 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200529 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300530 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200531 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300532 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200533 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300534 }
535out:
536 return ret;
537}
538
539static void wl1271_rx_streaming_enable_work(struct work_struct *work)
540{
541 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200542 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
543 rx_streaming_enable_work);
544 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300545
546 mutex_lock(&wl->mutex);
547
Eliad Peller0744bdb2011-10-10 10:13:05 +0200548 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200549 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300550 (!wl->conf.rx_streaming.always &&
551 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
552 goto out;
553
554 if (!wl->conf.rx_streaming.interval)
555 goto out;
556
557 ret = wl1271_ps_elp_wakeup(wl);
558 if (ret < 0)
559 goto out;
560
Eliad Peller9eb599e2011-10-10 10:12:59 +0200561 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300562 if (ret < 0)
563 goto out_sleep;
564
565 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200566 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300567 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
568
569out_sleep:
570 wl1271_ps_elp_sleep(wl);
571out:
572 mutex_unlock(&wl->mutex);
573}
574
575static void wl1271_rx_streaming_disable_work(struct work_struct *work)
576{
577 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200578 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
579 rx_streaming_disable_work);
580 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300581
582 mutex_lock(&wl->mutex);
583
Eliad Peller0744bdb2011-10-10 10:13:05 +0200584 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300585 goto out;
586
587 ret = wl1271_ps_elp_wakeup(wl);
588 if (ret < 0)
589 goto out;
590
Eliad Peller9eb599e2011-10-10 10:12:59 +0200591 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300592 if (ret)
593 goto out_sleep;
594
595out_sleep:
596 wl1271_ps_elp_sleep(wl);
597out:
598 mutex_unlock(&wl->mutex);
599}
600
601static void wl1271_rx_streaming_timer(unsigned long data)
602{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200603 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
604 struct wl1271 *wl = wlvif->wl;
605 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300606}
607
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300608static void wl1271_conf_init(struct wl1271 *wl)
609{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300610
611 /*
612 * This function applies the default configuration to the driver. This
613 * function is invoked upon driver load (spi probe.)
614 *
615 * The configuration is stored in a run-time structure in order to
616 * facilitate for run-time adjustment of any of the parameters. Making
617 * changes to the configuration structure will apply the new values on
618 * the next interface up (wl1271_op_start.)
619 */
620
621 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300622 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300623
Ido Yariv95dac04f2011-06-06 14:57:06 +0300624 /* Adjust settings according to optional module parameters */
625 if (fwlog_param) {
626 if (!strcmp(fwlog_param, "continuous")) {
627 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
628 } else if (!strcmp(fwlog_param, "ondemand")) {
629 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
630 } else if (!strcmp(fwlog_param, "dbgpins")) {
631 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
632 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
633 } else if (!strcmp(fwlog_param, "disable")) {
634 wl->conf.fwlog.mem_blocks = 0;
635 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
636 } else {
637 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
638 }
639 }
640}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300641
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300642static int wl1271_plt_init(struct wl1271 *wl)
643{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200644 struct conf_tx_ac_category *conf_ac;
645 struct conf_tx_tid *conf_tid;
646 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300647
Shahar Levi49d750ca2011-03-06 16:32:09 +0200648 if (wl->chip.id == CHIP_ID_1283_PG20)
649 ret = wl128x_cmd_general_parms(wl);
650 else
651 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200652 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200653 return ret;
654
Shahar Levi49d750ca2011-03-06 16:32:09 +0200655 if (wl->chip.id == CHIP_ID_1283_PG20)
656 ret = wl128x_cmd_radio_parms(wl);
657 else
658 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200659 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200660 return ret;
661
Shahar Levi49d750ca2011-03-06 16:32:09 +0200662 if (wl->chip.id != CHIP_ID_1283_PG20) {
663 ret = wl1271_cmd_ext_radio_parms(wl);
664 if (ret < 0)
665 return ret;
666 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200667 if (ret < 0)
668 return ret;
669
Shahar Levi48a61472011-03-06 16:32:08 +0200670 /* Chip-specific initializations */
671 ret = wl1271_chip_specific_init(wl);
672 if (ret < 0)
673 return ret;
674
Eliad Peller92c77c72011-10-05 11:55:40 +0200675 ret = wl1271_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200676 if (ret < 0)
677 return ret;
678
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679 ret = wl1271_acx_init_mem_config(wl);
680 if (ret < 0)
681 return ret;
682
Luciano Coelho12419cc2010-02-18 13:25:44 +0200683 /* PHY layer config */
684 ret = wl1271_init_phy_config(wl);
685 if (ret < 0)
686 goto out_free_memmap;
687
688 ret = wl1271_acx_dco_itrim_params(wl);
689 if (ret < 0)
690 goto out_free_memmap;
691
692 /* Initialize connection monitoring thresholds */
Eliad Peller0603d892011-10-05 11:55:51 +0200693 ret = wl1271_acx_conn_monit_params(wl, NULL, false); /* TODO: fix */
Luciano Coelho12419cc2010-02-18 13:25:44 +0200694 if (ret < 0)
695 goto out_free_memmap;
696
697 /* Bluetooth WLAN coexistence */
698 ret = wl1271_init_pta(wl);
699 if (ret < 0)
700 goto out_free_memmap;
701
Shahar Leviff868432011-04-11 15:41:46 +0300702 /* FM WLAN coexistence */
703 ret = wl1271_acx_fm_coex(wl);
704 if (ret < 0)
705 goto out_free_memmap;
706
Luciano Coelho12419cc2010-02-18 13:25:44 +0200707 /* Energy detection */
708 ret = wl1271_init_energy_detection(wl);
709 if (ret < 0)
710 goto out_free_memmap;
711
Eliad Peller7f0979882011-08-14 13:17:06 +0300712 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600713 if (ret < 0)
714 goto out_free_memmap;
715
Luciano Coelho12419cc2010-02-18 13:25:44 +0200716 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100717 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200718 if (ret < 0)
719 goto out_free_memmap;
720
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200721 /* Default TID/AC configuration */
722 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200723 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200724 conf_ac = &wl->conf.tx.ac_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200725 /* TODO: fix */
726 ret = wl1271_acx_ac_cfg(wl, NULL, conf_ac->ac, conf_ac->cw_min,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200727 conf_ac->cw_max, conf_ac->aifsn,
728 conf_ac->tx_op_limit);
729 if (ret < 0)
730 goto out_free_memmap;
731
Luciano Coelho12419cc2010-02-18 13:25:44 +0200732 conf_tid = &wl->conf.tx.tid_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200733 /* TODO: fix */
734 ret = wl1271_acx_tid_cfg(wl, NULL, conf_tid->queue_id,
Luciano Coelho12419cc2010-02-18 13:25:44 +0200735 conf_tid->channel_type,
736 conf_tid->tsid,
737 conf_tid->ps_scheme,
738 conf_tid->ack_policy,
739 conf_tid->apsd_conf[0],
740 conf_tid->apsd_conf[1]);
741 if (ret < 0)
742 goto out_free_memmap;
743 }
744
Luciano Coelho12419cc2010-02-18 13:25:44 +0200745 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200746 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300747 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200748 goto out_free_memmap;
749
750 /* Configure for CAM power saving (ie. always active) */
751 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
752 if (ret < 0)
753 goto out_free_memmap;
754
755 /* configure PM */
756 ret = wl1271_acx_pm_config(wl);
757 if (ret < 0)
758 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300759
760 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200761
762 out_free_memmap:
763 kfree(wl->target_mem_map);
764 wl->target_mem_map = NULL;
765
766 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767}
768
Eliad Peller6e8cd332011-10-10 10:13:13 +0200769static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
770 struct wl12xx_vif *wlvif,
771 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200772{
Arik Nemtsovda032092011-08-25 12:43:15 +0300773 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200774
Arik Nemtsovb622d992011-02-23 00:22:31 +0200775 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300776 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200777
778 /*
779 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300780 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200781 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300782 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200783 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200784
Arik Nemtsovda032092011-08-25 12:43:15 +0300785 /*
786 * Start high-level PS if the STA is asleep with enough blocks in FW.
787 * Make an exception if this is the only connected station. In this
788 * case FW-memory congestion is not a problem.
789 */
790 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200791 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200792}
793
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300794static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200795 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300796 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200797{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200798 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200799 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300800 u8 hlid, cnt;
801
802 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200803
804 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
805 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
806 wl1271_debug(DEBUG_PSM,
807 "link ps prev 0x%x cur 0x%x changed 0x%x",
808 wl->ap_fw_ps_map, cur_fw_ps_map,
809 wl->ap_fw_ps_map ^ cur_fw_ps_map);
810
811 wl->ap_fw_ps_map = cur_fw_ps_map;
812 }
813
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200814 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
815 lnk = &wl->links[hlid];
816 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200817
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200818 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
819 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200820
Eliad Peller6e8cd332011-10-10 10:13:13 +0200821 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
822 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200823 }
824}
825
Eliad Peller4d56ad92011-08-14 13:17:05 +0300826static void wl12xx_fw_status(struct wl1271 *wl,
827 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200829 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200830 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200831 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300832 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300833 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834
Eliad Peller4d56ad92011-08-14 13:17:05 +0300835 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200836
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300837 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
838 "drv_rx_counter = %d, tx_results_counter = %d)",
839 status->intr,
840 status->fw_rx_counter,
841 status->drv_rx_counter,
842 status->tx_results_counter);
843
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300844 for (i = 0; i < NUM_TX_QUEUES; i++) {
845 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300846 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300847 (status->tx_released_pkts[i] -
848 wl->tx_pkts_freed[i]) & 0xff;
849
850 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
851 }
852
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300853 /* prevent wrap-around in total blocks counter */
854 if (likely(wl->tx_blocks_freed <=
855 le32_to_cpu(status->total_released_blks)))
856 freed_blocks = le32_to_cpu(status->total_released_blks) -
857 wl->tx_blocks_freed;
858 else
859 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
860 le32_to_cpu(status->total_released_blks);
861
Eliad Peller4d56ad92011-08-14 13:17:05 +0300862 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200863
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300864 wl->tx_allocated_blocks -= freed_blocks;
865
Eliad Peller4d56ad92011-08-14 13:17:05 +0300866 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200867
Eliad Peller4d56ad92011-08-14 13:17:05 +0300868 /*
869 * The FW might change the total number of TX memblocks before
870 * we get a notification about blocks being released. Thus, the
871 * available blocks calculation might yield a temporary result
872 * which is lower than the actual available blocks. Keeping in
873 * mind that only blocks that were allocated can be moved from
874 * TX to RX, tx_blocks_available should never decrease here.
875 */
876 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
877 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878
Ido Yariva5225502010-10-12 14:49:10 +0200879 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200880 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200881 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300882
Eliad Peller4d56ad92011-08-14 13:17:05 +0300883 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200884 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200885 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200886 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300887
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300888 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200889 getnstimeofday(&ts);
890 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
891 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300892}
893
Ido Yariva6208652011-03-01 15:14:41 +0200894static void wl1271_flush_deferred_work(struct wl1271 *wl)
895{
896 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200897
Ido Yariva6208652011-03-01 15:14:41 +0200898 /* Pass all received frames to the network stack */
899 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
900 ieee80211_rx_ni(wl->hw, skb);
901
902 /* Return sent skbs to the network stack */
903 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300904 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200905}
906
907static void wl1271_netstack_work(struct work_struct *work)
908{
909 struct wl1271 *wl =
910 container_of(work, struct wl1271, netstack_work);
911
912 do {
913 wl1271_flush_deferred_work(wl);
914 } while (skb_queue_len(&wl->deferred_rx_queue));
915}
916
917#define WL1271_IRQ_MAX_LOOPS 256
918
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300919static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300920{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300921 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300922 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200923 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200924 struct wl1271 *wl = (struct wl1271 *)cookie;
925 bool done = false;
926 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200927 unsigned long flags;
928
929 /* TX might be handled here, avoid redundant work */
930 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
931 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932
Ido Yariv341b7cd2011-03-31 10:07:01 +0200933 /*
934 * In case edge triggered interrupt must be used, we cannot iterate
935 * more than once without introducing race conditions with the hardirq.
936 */
937 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
938 loopcount = 1;
939
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300940 mutex_lock(&wl->mutex);
941
942 wl1271_debug(DEBUG_IRQ, "IRQ work");
943
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200944 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945 goto out;
946
Ido Yariva6208652011-03-01 15:14:41 +0200947 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948 if (ret < 0)
949 goto out;
950
Ido Yariva6208652011-03-01 15:14:41 +0200951 while (!done && loopcount--) {
952 /*
953 * In order to avoid a race with the hardirq, clear the flag
954 * before acknowledging the chip. Since the mutex is held,
955 * wl1271_ps_elp_wakeup cannot be called concurrently.
956 */
957 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
958 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200959
Eliad Peller4d56ad92011-08-14 13:17:05 +0300960 wl12xx_fw_status(wl, wl->fw_status);
961 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200962 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200963 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200964 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200965 continue;
966 }
967
Eliad Pellerccc83b02010-10-27 14:09:57 +0200968 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
969 wl1271_error("watchdog interrupt received! "
970 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300971 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200972
973 /* restarting the chip. ignore any other interrupt. */
974 goto out;
975 }
976
Ido Yariva6208652011-03-01 15:14:41 +0200977 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200978 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
979
Eliad Peller4d56ad92011-08-14 13:17:05 +0300980 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200981
Ido Yariva5225502010-10-12 14:49:10 +0200982 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200983 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200984 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300985 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200986 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200987 /*
988 * In order to avoid starvation of the TX path,
989 * call the work function directly.
990 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200991 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200992 } else {
993 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200994 }
995
Ido Yariv8aad2462011-03-01 15:14:38 +0200996 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300997 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200998 (wl->tx_results_count & 0xff))
999 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001000
1001 /* Make sure the deferred queues don't get too long */
1002 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1003 skb_queue_len(&wl->deferred_rx_queue);
1004 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1005 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001006 }
1007
1008 if (intr & WL1271_ACX_INTR_EVENT_A) {
1009 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1010 wl1271_event_handle(wl, 0);
1011 }
1012
1013 if (intr & WL1271_ACX_INTR_EVENT_B) {
1014 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1015 wl1271_event_handle(wl, 1);
1016 }
1017
1018 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1019 wl1271_debug(DEBUG_IRQ,
1020 "WL1271_ACX_INTR_INIT_COMPLETE");
1021
1022 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1023 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024 }
1025
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026 wl1271_ps_elp_sleep(wl);
1027
1028out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001029 spin_lock_irqsave(&wl->wl_lock, flags);
1030 /* In case TX was not handled here, queue TX work */
1031 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1032 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001033 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001034 ieee80211_queue_work(wl->hw, &wl->tx_work);
1035 spin_unlock_irqrestore(&wl->wl_lock, flags);
1036
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001038
1039 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040}
1041
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042static int wl1271_fetch_firmware(struct wl1271 *wl)
1043{
1044 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001045 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046 int ret;
1047
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001048 if (wl->chip.id == CHIP_ID_1283_PG20)
1049 fw_name = WL128X_FW_NAME;
1050 else
1051 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001052
1053 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1054
Felipe Balbia390e852011-10-06 10:07:44 +03001055 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056
1057 if (ret < 0) {
1058 wl1271_error("could not get firmware: %d", ret);
1059 return ret;
1060 }
1061
1062 if (fw->size % 4) {
1063 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1064 fw->size);
1065 ret = -EILSEQ;
1066 goto out;
1067 }
1068
Arik Nemtsov166d5042010-10-16 21:44:57 +02001069 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001070 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001071 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001072
1073 if (!wl->fw) {
1074 wl1271_error("could not allocate memory for the firmware");
1075 ret = -ENOMEM;
1076 goto out;
1077 }
1078
1079 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080 ret = 0;
1081
1082out:
1083 release_firmware(fw);
1084
1085 return ret;
1086}
1087
1088static int wl1271_fetch_nvs(struct wl1271 *wl)
1089{
1090 const struct firmware *fw;
1091 int ret;
1092
Felipe Balbia390e852011-10-06 10:07:44 +03001093 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001094
1095 if (ret < 0) {
1096 wl1271_error("could not get nvs file: %d", ret);
1097 return ret;
1098 }
1099
Shahar Levibc765bf2011-03-06 16:32:10 +02001100 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001101
1102 if (!wl->nvs) {
1103 wl1271_error("could not allocate memory for the nvs file");
1104 ret = -ENOMEM;
1105 goto out;
1106 }
1107
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001108 wl->nvs_len = fw->size;
1109
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001110out:
1111 release_firmware(fw);
1112
1113 return ret;
1114}
1115
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001116void wl12xx_queue_recovery_work(struct wl1271 *wl)
1117{
1118 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1119 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1120}
1121
Ido Yariv95dac04f2011-06-06 14:57:06 +03001122size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1123{
1124 size_t len = 0;
1125
1126 /* The FW log is a length-value list, find where the log end */
1127 while (len < maxlen) {
1128 if (memblock[len] == 0)
1129 break;
1130 if (len + memblock[len] + 1 > maxlen)
1131 break;
1132 len += memblock[len] + 1;
1133 }
1134
1135 /* Make sure we have enough room */
1136 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1137
1138 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1139 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1140 wl->fwlog_size += len;
1141
1142 return len;
1143}
1144
1145static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1146{
1147 u32 addr;
1148 u32 first_addr;
1149 u8 *block;
1150
1151 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1152 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1153 (wl->conf.fwlog.mem_blocks == 0))
1154 return;
1155
1156 wl1271_info("Reading FW panic log");
1157
1158 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1159 if (!block)
1160 return;
1161
1162 /*
1163 * Make sure the chip is awake and the logger isn't active.
1164 * This might fail if the firmware hanged.
1165 */
1166 if (!wl1271_ps_elp_wakeup(wl))
1167 wl12xx_cmd_stop_fwlog(wl);
1168
1169 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001170 wl12xx_fw_status(wl, wl->fw_status);
1171 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001172 if (!first_addr)
1173 goto out;
1174
1175 /* Traverse the memory blocks linked list */
1176 addr = first_addr;
1177 do {
1178 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1179 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1180 false);
1181
1182 /*
1183 * Memory blocks are linked to one another. The first 4 bytes
1184 * of each memory block hold the hardware address of the next
1185 * one. The last memory block points to the first one.
1186 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001187 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001188 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1189 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1190 break;
1191 } while (addr && (addr != first_addr));
1192
1193 wake_up_interruptible(&wl->fwlog_waitq);
1194
1195out:
1196 kfree(block);
1197}
1198
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001199static void wl1271_recovery_work(struct work_struct *work)
1200{
1201 struct wl1271 *wl =
1202 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001203 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001204 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001205
1206 mutex_lock(&wl->mutex);
1207
1208 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001209 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001210
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001211 /* Avoid a recursive recovery */
1212 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1213
Ido Yariv95dac04f2011-06-06 14:57:06 +03001214 wl12xx_read_fwlog_panic(wl);
1215
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001216 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1217 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001218
Eliad Peller2a5bff02011-08-25 18:10:59 +03001219 BUG_ON(bug_on_recovery);
1220
Oz Krakowskib992c682011-06-26 10:36:02 +03001221 /*
1222 * Advance security sequence number to overcome potential progress
1223 * in the firmware during recovery. This doens't hurt if the network is
1224 * not encrypted.
1225 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001226 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001227 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001228 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001229 wlvif->tx_security_seq +=
1230 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1231 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001232
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001233 /* Prevent spurious TX during FW restart */
1234 ieee80211_stop_queues(wl->hw);
1235
Luciano Coelho33c2c062011-05-10 14:46:02 +03001236 if (wl->sched_scanning) {
1237 ieee80211_sched_scan_stopped(wl->hw);
1238 wl->sched_scanning = false;
1239 }
1240
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001241 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001242 while (!list_empty(&wl->wlvif_list)) {
1243 wlvif = list_first_entry(&wl->wlvif_list,
1244 struct wl12xx_vif, list);
1245 vif = wl12xx_wlvif_to_vif(wlvif);
1246 __wl1271_op_remove_interface(wl, vif, false);
1247 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001248 mutex_unlock(&wl->mutex);
1249 wl1271_op_stop(wl->hw);
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);
Eliad Pellerf0277432011-10-10 10:13:14 +02001260 return;
1261out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001262 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 Oikarinen01ac17ec2009-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
1331 ret = wl1271_setup(wl);
1332 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001333 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001334 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001335 case CHIP_ID_1283_PG20:
1336 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1337 wl->chip.id);
1338
1339 ret = wl1271_setup(wl);
1340 if (ret < 0)
1341 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001342
Ido Yariv0da13da2011-03-31 10:06:58 +02001343 if (wl1271_set_block_size(wl))
1344 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001345 break;
1346 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001348 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001349 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001350 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001351 }
1352
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001353 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001354 ret = wl1271_fetch_firmware(wl);
1355 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001356 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357 }
1358
1359 /* No NVS from netlink, try to get it from the filesystem */
1360 if (wl->nvs == NULL) {
1361 ret = wl1271_fetch_nvs(wl);
1362 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001363 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364 }
1365
1366out:
1367 return ret;
1368}
1369
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370int wl1271_plt_start(struct wl1271 *wl)
1371{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001372 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001373 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001374 int ret;
1375
1376 mutex_lock(&wl->mutex);
1377
1378 wl1271_notice("power up");
1379
1380 if (wl->state != WL1271_STATE_OFF) {
1381 wl1271_error("cannot go into PLT state because not "
1382 "in off state: %d", wl->state);
1383 ret = -EBUSY;
1384 goto out;
1385 }
1386
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001387 while (retries) {
1388 retries--;
1389 ret = wl1271_chip_wakeup(wl);
1390 if (ret < 0)
1391 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001392
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001393 ret = wl1271_boot(wl);
1394 if (ret < 0)
1395 goto power_off;
1396
1397 ret = wl1271_plt_init(wl);
1398 if (ret < 0)
1399 goto irq_disable;
1400
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001401 wl->state = WL1271_STATE_PLT;
1402 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001403 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001404
Gery Kahn6f07b722011-07-18 14:21:49 +03001405 /* update hw/fw version info in wiphy struct */
1406 wiphy->hw_version = wl->chip.id;
1407 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1408 sizeof(wiphy->fw_version));
1409
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001410 goto out;
1411
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001412irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001413 mutex_unlock(&wl->mutex);
1414 /* Unlocking the mutex in the middle of handling is
1415 inherently unsafe. In this case we deem it safe to do,
1416 because we need to let any possibly pending IRQ out of
1417 the system (and while we are WL1271_STATE_OFF the IRQ
1418 work function will not do anything.) Also, any other
1419 possible concurrent operations will fail due to the
1420 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001421 wl1271_disable_interrupts(wl);
1422 wl1271_flush_deferred_work(wl);
1423 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001424 mutex_lock(&wl->mutex);
1425power_off:
1426 wl1271_power_off(wl);
1427 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001428
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001429 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1430 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001431out:
1432 mutex_unlock(&wl->mutex);
1433
1434 return ret;
1435}
1436
Luciano Coelho4623ec72011-03-21 19:26:41 +02001437static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438{
1439 int ret = 0;
1440
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441 wl1271_notice("power down");
1442
1443 if (wl->state != WL1271_STATE_PLT) {
1444 wl1271_error("cannot power down because not in PLT "
1445 "state: %d", wl->state);
1446 ret = -EBUSY;
1447 goto out;
1448 }
1449
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001450 wl1271_power_off(wl);
1451
1452 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001453 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001456 wl1271_disable_interrupts(wl);
1457 wl1271_flush_deferred_work(wl);
1458 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001459 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001460 mutex_lock(&wl->mutex);
1461out:
1462 return ret;
1463}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001464
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001465int wl1271_plt_stop(struct wl1271 *wl)
1466{
1467 int ret;
1468
1469 mutex_lock(&wl->mutex);
1470 ret = __wl1271_plt_stop(wl);
1471 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001472 return ret;
1473}
1474
Johannes Berg7bb45682011-02-24 14:42:06 +01001475static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001476{
1477 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001478 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1479 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001480 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001481 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001482 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001483 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001484
Eliad Peller0f168012011-10-11 13:52:25 +02001485 if (vif)
1486 wlvif = wl12xx_vif_to_data(vif);
1487
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001488 mapping = skb_get_queue_mapping(skb);
1489 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001490
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001491 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001492
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001493 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001494
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001495 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001496 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001497 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001498 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
1499 dev_kfree_skb(skb);
1500 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001501 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001502
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001503 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1504 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1505
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001506 wl->tx_queue_count[q]++;
1507
1508 /*
1509 * The workqueue is slow to process the tx_queue and we need stop
1510 * the queue here, otherwise the queue will get too long.
1511 */
1512 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1513 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1514 ieee80211_stop_queue(wl->hw, mapping);
1515 set_bit(q, &wl->stopped_queues_map);
1516 }
1517
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001518 /*
1519 * The chip specific setup must run before the first TX packet -
1520 * before that, the tx_work will not be initialized!
1521 */
1522
Ido Yarivb07d4032011-03-01 15:14:43 +02001523 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1524 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001525 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001526
Arik Nemtsov04216da2011-08-14 13:17:38 +03001527out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001528 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001529}
1530
Shahar Leviae47c452011-03-06 16:32:14 +02001531int wl1271_tx_dummy_packet(struct wl1271 *wl)
1532{
Ido Yariv990f5de2011-03-31 10:06:59 +02001533 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001534 int q;
1535
1536 /* no need to queue a new dummy packet if one is already pending */
1537 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1538 return 0;
1539
1540 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001541
Ido Yariv990f5de2011-03-31 10:06:59 +02001542 spin_lock_irqsave(&wl->wl_lock, flags);
1543 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001544 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001545 spin_unlock_irqrestore(&wl->wl_lock, flags);
1546
1547 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1548 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001549 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001550
1551 /*
1552 * If the FW TX is busy, TX work will be scheduled by the threaded
1553 * interrupt handler function
1554 */
1555 return 0;
1556}
1557
1558/*
1559 * The size of the dummy packet should be at least 1400 bytes. However, in
1560 * order to minimize the number of bus transactions, aligning it to 512 bytes
1561 * boundaries could be beneficial, performance wise
1562 */
1563#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1564
Luciano Coelhocf27d862011-04-01 21:08:23 +03001565static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001566{
1567 struct sk_buff *skb;
1568 struct ieee80211_hdr_3addr *hdr;
1569 unsigned int dummy_packet_size;
1570
1571 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1572 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1573
1574 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001575 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001576 wl1271_warning("Failed to allocate a dummy packet skb");
1577 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001578 }
1579
1580 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1581
1582 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1583 memset(hdr, 0, sizeof(*hdr));
1584 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001585 IEEE80211_STYPE_NULLFUNC |
1586 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001587
Ido Yariv990f5de2011-03-31 10:06:59 +02001588 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001589
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001590 /* Dummy packets require the TID to be management */
1591 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001592
1593 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001594 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001595 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001596
Ido Yariv990f5de2011-03-31 10:06:59 +02001597 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001598}
1599
Ido Yariv990f5de2011-03-31 10:06:59 +02001600
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001601static struct notifier_block wl1271_dev_notifier = {
1602 .notifier_call = wl1271_dev_notify,
1603};
1604
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001605#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001606static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1607 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001608{
Eliad Pellere85d1622011-06-27 13:06:43 +03001609 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001610
Eliad Peller94390642011-05-13 11:57:13 +03001611 mutex_lock(&wl->mutex);
1612
Eliad Pellerba8447f2011-10-10 10:13:00 +02001613 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001614 goto out_unlock;
1615
Eliad Peller94390642011-05-13 11:57:13 +03001616 ret = wl1271_ps_elp_wakeup(wl);
1617 if (ret < 0)
1618 goto out_unlock;
1619
1620 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001621 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001622 DECLARE_COMPLETION_ONSTACK(compl);
1623
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001624 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001625 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001626 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001627 if (ret < 0)
1628 goto out_sleep;
1629
1630 /* we must unlock here so we will be able to get events */
1631 wl1271_ps_elp_sleep(wl);
1632 mutex_unlock(&wl->mutex);
1633
1634 ret = wait_for_completion_timeout(
1635 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1636 if (ret <= 0) {
1637 wl1271_warning("couldn't enter ps mode!");
1638 ret = -EBUSY;
1639 goto out;
1640 }
1641
1642 /* take mutex again, and wakeup */
1643 mutex_lock(&wl->mutex);
1644
1645 ret = wl1271_ps_elp_wakeup(wl);
1646 if (ret < 0)
1647 goto out_unlock;
1648 }
1649out_sleep:
1650 wl1271_ps_elp_sleep(wl);
1651out_unlock:
1652 mutex_unlock(&wl->mutex);
1653out:
1654 return ret;
1655
1656}
1657
Eliad Peller0603d892011-10-05 11:55:51 +02001658static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1659 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001660{
Eliad Pellere85d1622011-06-27 13:06:43 +03001661 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001662
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001663 mutex_lock(&wl->mutex);
1664
Eliad Peller53d40d02011-10-10 10:13:02 +02001665 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001666 goto out_unlock;
1667
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001668 ret = wl1271_ps_elp_wakeup(wl);
1669 if (ret < 0)
1670 goto out_unlock;
1671
Eliad Peller0603d892011-10-05 11:55:51 +02001672 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001673
1674 wl1271_ps_elp_sleep(wl);
1675out_unlock:
1676 mutex_unlock(&wl->mutex);
1677 return ret;
1678
1679}
1680
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001681static int wl1271_configure_suspend(struct wl1271 *wl,
1682 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001683{
Eliad Peller536129c2011-10-05 11:55:45 +02001684 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001685 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001686 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001687 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001688 return 0;
1689}
1690
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001691static void wl1271_configure_resume(struct wl1271 *wl,
1692 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001693{
1694 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001695 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1696 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001697
1698 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001699 return;
1700
1701 mutex_lock(&wl->mutex);
1702 ret = wl1271_ps_elp_wakeup(wl);
1703 if (ret < 0)
1704 goto out;
1705
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001706 if (is_sta) {
1707 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001708 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001709 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001710 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001711 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001712 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001713 }
Eliad Peller94390642011-05-13 11:57:13 +03001714
1715 wl1271_ps_elp_sleep(wl);
1716out:
1717 mutex_unlock(&wl->mutex);
1718}
1719
Eliad Peller402e48612011-05-13 11:57:09 +03001720static int wl1271_op_suspend(struct ieee80211_hw *hw,
1721 struct cfg80211_wowlan *wow)
1722{
1723 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001724 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001725 int ret;
1726
Eliad Peller402e48612011-05-13 11:57:09 +03001727 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001728 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001729
Eliad Peller4a859df2011-06-06 12:21:52 +03001730 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001731 wl12xx_for_each_wlvif(wl, wlvif) {
1732 ret = wl1271_configure_suspend(wl, wlvif);
1733 if (ret < 0) {
1734 wl1271_warning("couldn't prepare device to suspend");
1735 return ret;
1736 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001737 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001738 /* flush any remaining work */
1739 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001740
1741 /*
1742 * disable and re-enable interrupts in order to flush
1743 * the threaded_irq
1744 */
1745 wl1271_disable_interrupts(wl);
1746
1747 /*
1748 * set suspended flag to avoid triggering a new threaded_irq
1749 * work. no need for spinlock as interrupts are disabled.
1750 */
1751 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1752
1753 wl1271_enable_interrupts(wl);
1754 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001755 wl12xx_for_each_wlvif(wl, wlvif) {
1756 flush_delayed_work(&wlvif->pspoll_work);
1757 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001758 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 Peller6e8cd332011-10-10 10:13:13 +02001766 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001767 unsigned long flags;
1768 bool run_irq_work = false;
1769
Eliad Peller402e48612011-05-13 11:57:09 +03001770 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1771 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001772 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001773
1774 /*
1775 * re-enable irq_work enqueuing, and call irq_work directly if
1776 * there is a pending work.
1777 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001778 spin_lock_irqsave(&wl->wl_lock, flags);
1779 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1780 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1781 run_irq_work = true;
1782 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001783
Eliad Peller4a859df2011-06-06 12:21:52 +03001784 if (run_irq_work) {
1785 wl1271_debug(DEBUG_MAC80211,
1786 "run postponed irq_work directly");
1787 wl1271_irq(0, wl);
1788 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001789 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001790 wl12xx_for_each_wlvif(wl, wlvif) {
1791 wl1271_configure_resume(wl, wlvif);
1792 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001793 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001794
Eliad Peller402e48612011-05-13 11:57:09 +03001795 return 0;
1796}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001797#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001798
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001799static int wl1271_op_start(struct ieee80211_hw *hw)
1800{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001801 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1802
1803 /*
1804 * We have to delay the booting of the hardware because
1805 * we need to know the local MAC address before downloading and
1806 * initializing the firmware. The MAC address cannot be changed
1807 * after boot, and without the proper MAC address, the firmware
1808 * will not function properly.
1809 *
1810 * The MAC address is first known when the corresponding interface
1811 * is added. That is where we will initialize the hardware.
1812 */
1813
1814 return 0;
1815}
1816
1817static void wl1271_op_stop(struct ieee80211_hw *hw)
1818{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001819 struct wl1271 *wl = hw->priv;
1820 int i;
1821
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001822 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001823
Eliad Peller10c8cd02011-10-10 10:13:06 +02001824 mutex_lock(&wl->mutex);
1825 if (wl->state == WL1271_STATE_OFF) {
1826 mutex_unlock(&wl->mutex);
1827 return;
1828 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001829 /*
1830 * this must be before the cancel_work calls below, so that the work
1831 * functions don't perform further work.
1832 */
1833 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001834 mutex_unlock(&wl->mutex);
1835
1836 mutex_lock(&wl_list_mutex);
1837 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001838 mutex_unlock(&wl_list_mutex);
1839
1840 wl1271_disable_interrupts(wl);
1841 wl1271_flush_deferred_work(wl);
1842 cancel_delayed_work_sync(&wl->scan_complete_work);
1843 cancel_work_sync(&wl->netstack_work);
1844 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001845 cancel_delayed_work_sync(&wl->elp_work);
1846
1847 /* let's notify MAC80211 about the remaining pending TX frames */
1848 wl12xx_tx_reset(wl, true);
1849 mutex_lock(&wl->mutex);
1850
1851 wl1271_power_off(wl);
1852
1853 wl->band = IEEE80211_BAND_2GHZ;
1854
1855 wl->rx_counter = 0;
1856 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1857 wl->tx_blocks_available = 0;
1858 wl->tx_allocated_blocks = 0;
1859 wl->tx_results_count = 0;
1860 wl->tx_packets_count = 0;
1861 wl->time_offset = 0;
1862 wl->vif = NULL;
1863 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1864 wl->ap_fw_ps_map = 0;
1865 wl->ap_ps_map = 0;
1866 wl->sched_scanning = false;
1867 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1868 memset(wl->links_map, 0, sizeof(wl->links_map));
1869 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1870 wl->active_sta_count = 0;
1871
1872 /* The system link is always allocated */
1873 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1874
1875 /*
1876 * this is performed after the cancel_work calls and the associated
1877 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1878 * get executed before all these vars have been reset.
1879 */
1880 wl->flags = 0;
1881
1882 wl->tx_blocks_freed = 0;
1883
1884 for (i = 0; i < NUM_TX_QUEUES; i++) {
1885 wl->tx_pkts_freed[i] = 0;
1886 wl->tx_allocated_pkts[i] = 0;
1887 }
1888
1889 wl1271_debugfs_reset(wl);
1890
1891 kfree(wl->fw_status);
1892 wl->fw_status = NULL;
1893 kfree(wl->tx_res_if);
1894 wl->tx_res_if = NULL;
1895 kfree(wl->target_mem_map);
1896 wl->target_mem_map = NULL;
1897
1898 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001899}
1900
Eliad Pellere5a359f2011-10-10 10:13:15 +02001901static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1902{
1903 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1904 WL12XX_MAX_RATE_POLICIES);
1905 if (policy >= WL12XX_MAX_RATE_POLICIES)
1906 return -EBUSY;
1907
1908 __set_bit(policy, wl->rate_policies_map);
1909 *idx = policy;
1910 return 0;
1911}
1912
1913static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1914{
1915 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1916 return;
1917
1918 __clear_bit(*idx, wl->rate_policies_map);
1919 *idx = WL12XX_MAX_RATE_POLICIES;
1920}
1921
Eliad Peller536129c2011-10-05 11:55:45 +02001922static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001923{
Eliad Peller536129c2011-10-05 11:55:45 +02001924 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001925 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001926 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001927 return WL1271_ROLE_P2P_GO;
1928 else
1929 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001930
1931 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001932 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001933 return WL1271_ROLE_P2P_CL;
1934 else
1935 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001936
Eliad Peller227e81e2011-08-14 13:17:26 +03001937 case BSS_TYPE_IBSS:
1938 return WL1271_ROLE_IBSS;
1939
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001940 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001941 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001942 }
1943 return WL12XX_INVALID_ROLE_TYPE;
1944}
1945
Eliad Peller83587502011-10-10 10:12:53 +02001946static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001947{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001948 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001949 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001950
Eliad Peller48e93e42011-10-10 10:12:58 +02001951 /* clear everything but the persistent data */
1952 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001953
1954 switch (ieee80211_vif_type_p2p(vif)) {
1955 case NL80211_IFTYPE_P2P_CLIENT:
1956 wlvif->p2p = 1;
1957 /* fall-through */
1958 case NL80211_IFTYPE_STATION:
1959 wlvif->bss_type = BSS_TYPE_STA_BSS;
1960 break;
1961 case NL80211_IFTYPE_ADHOC:
1962 wlvif->bss_type = BSS_TYPE_IBSS;
1963 break;
1964 case NL80211_IFTYPE_P2P_GO:
1965 wlvif->p2p = 1;
1966 /* fall-through */
1967 case NL80211_IFTYPE_AP:
1968 wlvif->bss_type = BSS_TYPE_AP_BSS;
1969 break;
1970 default:
1971 wlvif->bss_type = MAX_BSS_TYPE;
1972 return -EOPNOTSUPP;
1973 }
1974
Eliad Peller0603d892011-10-05 11:55:51 +02001975 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001976 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001977 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001978
Eliad Pellere936bbe2011-10-05 11:55:56 +02001979 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1980 wlvif->bss_type == BSS_TYPE_IBSS) {
1981 /* init sta/ibss data */
1982 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001983 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1984 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1985 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001986 } else {
1987 /* init ap data */
1988 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1989 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001990 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1991 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1992 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1993 wl12xx_allocate_rate_policy(wl,
1994 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001995 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001996
Eliad Peller83587502011-10-10 10:12:53 +02001997 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1998 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001999 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002000 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002001 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02002002 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
2003
Eliad Peller1b92f152011-10-10 10:13:09 +02002004 /*
2005 * mac80211 configures some values globally, while we treat them
2006 * per-interface. thus, on init, we have to copy them from wl
2007 */
2008 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02002009 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02002010 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02002011
Eliad Peller9eb599e2011-10-10 10:12:59 +02002012 INIT_WORK(&wlvif->rx_streaming_enable_work,
2013 wl1271_rx_streaming_enable_work);
2014 INIT_WORK(&wlvif->rx_streaming_disable_work,
2015 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02002016 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02002017 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02002018
Eliad Peller9eb599e2011-10-10 10:12:59 +02002019 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
2020 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002021 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002022}
2023
Eliad Peller1d095472011-10-10 10:12:49 +02002024static bool wl12xx_init_fw(struct wl1271 *wl)
2025{
2026 int retries = WL1271_BOOT_RETRIES;
2027 bool booted = false;
2028 struct wiphy *wiphy = wl->hw->wiphy;
2029 int ret;
2030
2031 while (retries) {
2032 retries--;
2033 ret = wl1271_chip_wakeup(wl);
2034 if (ret < 0)
2035 goto power_off;
2036
2037 ret = wl1271_boot(wl);
2038 if (ret < 0)
2039 goto power_off;
2040
2041 ret = wl1271_hw_init(wl);
2042 if (ret < 0)
2043 goto irq_disable;
2044
2045 booted = true;
2046 break;
2047
2048irq_disable:
2049 mutex_unlock(&wl->mutex);
2050 /* Unlocking the mutex in the middle of handling is
2051 inherently unsafe. In this case we deem it safe to do,
2052 because we need to let any possibly pending IRQ out of
2053 the system (and while we are WL1271_STATE_OFF the IRQ
2054 work function will not do anything.) Also, any other
2055 possible concurrent operations will fail due to the
2056 current state, hence the wl1271 struct should be safe. */
2057 wl1271_disable_interrupts(wl);
2058 wl1271_flush_deferred_work(wl);
2059 cancel_work_sync(&wl->netstack_work);
2060 mutex_lock(&wl->mutex);
2061power_off:
2062 wl1271_power_off(wl);
2063 }
2064
2065 if (!booted) {
2066 wl1271_error("firmware boot failed despite %d retries",
2067 WL1271_BOOT_RETRIES);
2068 goto out;
2069 }
2070
2071 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2072
2073 /* update hw/fw version info in wiphy struct */
2074 wiphy->hw_version = wl->chip.id;
2075 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2076 sizeof(wiphy->fw_version));
2077
2078 /*
2079 * Now we know if 11a is supported (info from the NVS), so disable
2080 * 11a channels if not supported
2081 */
2082 if (!wl->enable_11a)
2083 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2084
2085 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2086 wl->enable_11a ? "" : "not ");
2087
2088 wl->state = WL1271_STATE_ON;
2089out:
2090 return booted;
2091}
2092
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002093static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2094 struct ieee80211_vif *vif)
2095{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002096 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002097 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002098 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002099 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002100 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002101
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002102 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002103 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002104
2105 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002106 ret = wl1271_ps_elp_wakeup(wl);
2107 if (ret < 0)
2108 goto out_unlock;
2109
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002110 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002111 wl1271_debug(DEBUG_MAC80211,
2112 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002113 ret = -EBUSY;
2114 goto out;
2115 }
2116
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002117 /*
2118 * in some very corner case HW recovery scenarios its possible to
2119 * get here before __wl1271_op_remove_interface is complete, so
2120 * opt out if that is the case.
2121 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002122 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2123 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002124 ret = -EBUSY;
2125 goto out;
2126 }
2127
Eliad Peller83587502011-10-10 10:12:53 +02002128 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002129 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002130 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002131
Eliad Peller252efa42011-10-05 11:56:00 +02002132 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002133 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002134 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2135 ret = -EINVAL;
2136 goto out;
2137 }
Eliad Peller1d095472011-10-10 10:12:49 +02002138
Eliad Peller784f6942011-10-05 11:55:39 +02002139 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002140 * TODO: after the nvs issue will be solved, move this block
2141 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002142 */
Eliad Peller1d095472011-10-10 10:12:49 +02002143 if (wl->state == WL1271_STATE_OFF) {
2144 /*
2145 * we still need this in order to configure the fw
2146 * while uploading the nvs
2147 */
2148 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002149
Eliad Peller1d095472011-10-10 10:12:49 +02002150 booted = wl12xx_init_fw(wl);
2151 if (!booted) {
2152 ret = -EINVAL;
2153 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002154 }
Eliad Peller1d095472011-10-10 10:12:49 +02002155 }
Eliad Peller04e80792011-08-14 13:17:09 +03002156
Eliad Peller1d095472011-10-10 10:12:49 +02002157 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2158 wlvif->bss_type == BSS_TYPE_IBSS) {
2159 /*
2160 * The device role is a special role used for
2161 * rx and tx frames prior to association (as
2162 * the STA role can get packets only from
2163 * its associated bssid)
2164 */
Eliad Peller784f6942011-10-05 11:55:39 +02002165 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002166 WL1271_ROLE_DEVICE,
2167 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002168 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002169 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002170 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002171
Eliad Peller1d095472011-10-10 10:12:49 +02002172 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2173 role_type, &wlvif->role_id);
2174 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002175 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002176
2177 ret = wl1271_init_vif_specific(wl, vif);
2178 if (ret < 0)
2179 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002180
2181 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002182 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002183 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002184
2185 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2186 wl->ap_count++;
2187 else
2188 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002189out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002190 wl1271_ps_elp_sleep(wl);
2191out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002192 mutex_unlock(&wl->mutex);
2193
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002194 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002195 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002196 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002197 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002198
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002199 return ret;
2200}
2201
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002202static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002203 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002204 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002205{
Eliad Peller536129c2011-10-05 11:55:45 +02002206 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002207 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002208
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002209 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002210
Eliad Peller10c8cd02011-10-10 10:13:06 +02002211 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2212 return;
2213
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002214 /* because of hardware recovery, we may get here twice */
2215 if (wl->state != WL1271_STATE_ON)
2216 return;
2217
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002218 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002219
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002220 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002221 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002222 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002223
Eliad Pellerbaf62772011-10-10 10:12:52 +02002224 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2225 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002226 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002227 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002228 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002229 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002230 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002231 }
2232
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002233 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2234 /* disable active roles */
2235 ret = wl1271_ps_elp_wakeup(wl);
2236 if (ret < 0)
2237 goto deinit;
2238
Eliad Peller536129c2011-10-05 11:55:45 +02002239 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002240 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002241 if (ret < 0)
2242 goto deinit;
2243 }
2244
Eliad Peller0603d892011-10-05 11:55:51 +02002245 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002246 if (ret < 0)
2247 goto deinit;
2248
2249 wl1271_ps_elp_sleep(wl);
2250 }
2251deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002252 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002253 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002254
2255 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2256 wlvif->bss_type == BSS_TYPE_IBSS) {
2257 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2258 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2259 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2260 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2261 } else {
2262 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2263 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2264 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2265 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2266 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2267 wl12xx_free_rate_policy(wl,
2268 &wlvif->ap.ucast_rate_idx[i]);
2269 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002270
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002271 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002272 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002273 if (wl->last_wlvif == wlvif)
2274 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002275 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002276 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002277 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002278 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002279
Eliad Pellera4e41302011-10-11 11:49:15 +02002280 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2281 wl->ap_count--;
2282 else
2283 wl->sta_count--;
2284
Eliad Pellerbaf62772011-10-10 10:12:52 +02002285 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002286 del_timer_sync(&wlvif->rx_streaming_timer);
2287 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2288 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002289 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002290
Eliad Pellerbaf62772011-10-10 10:12:52 +02002291 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002292}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002293
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002294static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2295 struct ieee80211_vif *vif)
2296{
2297 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002298 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002299 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002300
2301 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002302
2303 if (wl->state == WL1271_STATE_OFF ||
2304 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2305 goto out;
2306
Juuso Oikarinen67353292010-11-18 15:19:02 +02002307 /*
2308 * wl->vif can be null here if someone shuts down the interface
2309 * just when hardware recovery has been started.
2310 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002311 wl12xx_for_each_wlvif(wl, iter) {
2312 if (iter != wlvif)
2313 continue;
2314
Eliad Peller536129c2011-10-05 11:55:45 +02002315 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002316 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002317 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002318 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002319out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002320 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002321 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002322}
2323
Eliad Peller87fbcb02011-10-05 11:55:41 +02002324static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2325 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002326{
2327 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002328 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002329
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002330 /*
2331 * One of the side effects of the JOIN command is that is clears
2332 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2333 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002334 * Currently the only valid scenario for JOIN during association
2335 * is on roaming, in which case we will also be given new keys.
2336 * Keep the below message for now, unless it starts bothering
2337 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002338 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002339 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002340 wl1271_info("JOIN while associated.");
2341
2342 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002343 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002344
Eliad Peller227e81e2011-08-14 13:17:26 +03002345 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002346 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002347 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002348 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002349 if (ret < 0)
2350 goto out;
2351
Eliad Pellerba8447f2011-10-10 10:13:00 +02002352 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002353 goto out;
2354
2355 /*
2356 * The join command disable the keep-alive mode, shut down its process,
2357 * and also clear the template config, so we need to reset it all after
2358 * the join. The acx_aid starts the keep-alive process, and the order
2359 * of the commands below is relevant.
2360 */
Eliad Peller0603d892011-10-05 11:55:51 +02002361 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002362 if (ret < 0)
2363 goto out;
2364
Eliad Peller0603d892011-10-05 11:55:51 +02002365 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002366 if (ret < 0)
2367 goto out;
2368
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002369 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002370 if (ret < 0)
2371 goto out;
2372
Eliad Peller0603d892011-10-05 11:55:51 +02002373 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2374 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002375 ACX_KEEP_ALIVE_TPL_VALID);
2376 if (ret < 0)
2377 goto out;
2378
2379out:
2380 return ret;
2381}
2382
Eliad Peller0603d892011-10-05 11:55:51 +02002383static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002384{
2385 int ret;
2386
Eliad Peller52630c52011-10-10 10:13:08 +02002387 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002388 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2389
Shahar Levi6d158ff2011-09-08 13:01:33 +03002390 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002391 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002392 }
2393
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002394 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002395 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002396 if (ret < 0)
2397 goto out;
2398
Oz Krakowskib992c682011-06-26 10:36:02 +03002399 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002400 wlvif->tx_security_last_seq_lsb = 0;
2401 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002402
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002403out:
2404 return ret;
2405}
2406
Eliad Peller87fbcb02011-10-05 11:55:41 +02002407static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002408{
Eliad Peller1b92f152011-10-10 10:13:09 +02002409 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002410 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002411}
2412
Eliad Peller251c1772011-08-14 13:17:17 +03002413static bool wl12xx_is_roc(struct wl1271 *wl)
2414{
2415 u8 role_id;
2416
2417 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2418 if (role_id >= WL12XX_MAX_ROLES)
2419 return false;
2420
2421 return true;
2422}
2423
Eliad Peller87fbcb02011-10-05 11:55:41 +02002424static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2425 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002426{
2427 int ret;
2428
2429 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002430 /* no need to croc if we weren't busy (e.g. during boot) */
2431 if (wl12xx_is_roc(wl)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002432 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002433 if (ret < 0)
2434 goto out;
2435
Eliad Peller7edebf52011-10-05 11:55:52 +02002436 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002437 if (ret < 0)
2438 goto out;
2439 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002440 wlvif->rate_set =
2441 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2442 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002443 if (ret < 0)
2444 goto out;
2445 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002446 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002447 ACX_KEEP_ALIVE_TPL_INVALID);
2448 if (ret < 0)
2449 goto out;
2450 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2451 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002452 /* The current firmware only supports sched_scan in idle */
2453 if (wl->sched_scanning) {
2454 wl1271_scan_sched_scan_stop(wl);
2455 ieee80211_sched_scan_stopped(wl->hw);
2456 }
2457
Eliad Peller7edebf52011-10-05 11:55:52 +02002458 ret = wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002459 if (ret < 0)
2460 goto out;
2461
Eliad Peller1b92f152011-10-10 10:13:09 +02002462 ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002463 if (ret < 0)
2464 goto out;
2465 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2466 }
2467
2468out:
2469 return ret;
2470}
2471
Eliad Peller9f259c42011-10-10 10:13:12 +02002472static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2473 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002474{
Eliad Peller9f259c42011-10-10 10:13:12 +02002475 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2476 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002477
2478 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2479
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002480 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002481 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002482 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002483 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002484 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002485 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002486 wlvif->band = conf->channel->band;
2487 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002488
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002489 if (!is_ap) {
2490 /*
2491 * FIXME: the mac80211 should really provide a fixed
2492 * rate to use here. for now, just use the smallest
2493 * possible rate for the band as a fixed rate for
2494 * association frames and other control messages.
2495 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002496 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002497 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002498
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002499 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002500 wl1271_tx_min_rate_get(wl,
2501 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002502 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002503 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002504 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002505 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002506
Eliad Pellerba8447f2011-10-10 10:13:00 +02002507 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2508 &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002509 if (wl12xx_is_roc(wl)) {
2510 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002511 ret = wl12xx_croc(wl,
2512 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002513 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002514 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002515 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002516 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002517 if (ret < 0)
2518 wl1271_warning("cmd join on channel "
2519 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002520 } else {
2521 /*
2522 * change the ROC channel. do it only if we are
2523 * not idle. otherwise, CROC will be called
2524 * anyway.
2525 */
2526 if (wl12xx_is_roc(wl) &&
2527 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002528 ret = wl12xx_croc(wl,
2529 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002530 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002531 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002532
Eliad Peller1b92f152011-10-10 10:13:09 +02002533 ret = wl12xx_roc(wl, wlvif,
Eliad Peller7edebf52011-10-05 11:55:52 +02002534 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002535 if (ret < 0)
2536 wl1271_warning("roc failed %d",
2537 ret);
2538 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002539 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002540 }
2541 }
2542
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002543 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002544 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002545 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002546 if (ret < 0)
2547 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002548 }
2549
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002550 /*
2551 * if mac80211 changes the PSM mode, make sure the mode is not
2552 * incorrectly changed after the pspoll failure active window.
2553 */
2554 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002555 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002556
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002557 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002558 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2559 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002560
2561 /*
2562 * We enter PSM only if we're already associated.
2563 * If we're not, we'll enter it when joining an SSID,
2564 * through the bss_info_changed() hook.
2565 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002566 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002567 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002568 ret = wl1271_ps_set_mode(wl, wlvif,
2569 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002570 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002571 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002572 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002573 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002574 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002575
Eliad Pellerc29bb002011-10-10 10:13:03 +02002576 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002577
Eliad Pellerc29bb002011-10-10 10:13:03 +02002578 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002579 ret = wl1271_ps_set_mode(wl, wlvif,
2580 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002581 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002582 }
2583
Eliad Peller6bd65022011-10-10 10:13:11 +02002584 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002585 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002586 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002587 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002588
Eliad Peller6bd65022011-10-10 10:13:11 +02002589 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002590 }
2591
Eliad Peller9f259c42011-10-10 10:13:12 +02002592 return 0;
2593}
2594
2595static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2596{
2597 struct wl1271 *wl = hw->priv;
2598 struct wl12xx_vif *wlvif;
2599 struct ieee80211_conf *conf = &hw->conf;
2600 int channel, ret = 0;
2601
2602 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2603
2604 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2605 " changed 0x%x",
2606 channel,
2607 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2608 conf->power_level,
2609 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2610 changed);
2611
2612 /*
2613 * mac80211 will go to idle nearly immediately after transmitting some
2614 * frames, such as the deauth. To make sure those frames reach the air,
2615 * wait here until the TX queue is fully flushed.
2616 */
2617 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2618 (conf->flags & IEEE80211_CONF_IDLE))
2619 wl1271_tx_flush(wl);
2620
2621 mutex_lock(&wl->mutex);
2622
2623 /* we support configuring the channel and band even while off */
2624 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2625 wl->band = conf->channel->band;
2626 wl->channel = channel;
2627 }
2628
2629 if (changed & IEEE80211_CONF_CHANGE_POWER)
2630 wl->power_level = conf->power_level;
2631
2632 if (unlikely(wl->state == WL1271_STATE_OFF))
2633 goto out;
2634
2635 ret = wl1271_ps_elp_wakeup(wl);
2636 if (ret < 0)
2637 goto out;
2638
2639 /* configure each interface */
2640 wl12xx_for_each_wlvif(wl, wlvif) {
2641 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2642 if (ret < 0)
2643 goto out_sleep;
2644 }
2645
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002646out_sleep:
2647 wl1271_ps_elp_sleep(wl);
2648
2649out:
2650 mutex_unlock(&wl->mutex);
2651
2652 return ret;
2653}
2654
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002655struct wl1271_filter_params {
2656 bool enabled;
2657 int mc_list_length;
2658 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2659};
2660
Jiri Pirko22bedad2010-04-01 21:22:57 +00002661static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2662 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002663{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002664 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002665 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002666 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002667
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002668 if (unlikely(wl->state == WL1271_STATE_OFF))
2669 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002670
Juuso Oikarinen74441132009-10-13 12:47:53 +03002671 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002672 if (!fp) {
2673 wl1271_error("Out of memory setting filters.");
2674 return 0;
2675 }
2676
2677 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002678 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002679 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2680 fp->enabled = false;
2681 } else {
2682 fp->enabled = true;
2683 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002684 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002685 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002686 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002687 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002688 }
2689
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002690 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002691}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002692
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002693#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2694 FIF_ALLMULTI | \
2695 FIF_FCSFAIL | \
2696 FIF_BCN_PRBRESP_PROMISC | \
2697 FIF_CONTROL | \
2698 FIF_OTHER_BSS)
2699
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002700static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2701 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002702 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002703{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002704 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002705 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002706 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002707
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002708 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002709
Arik Nemtsov7d057862010-10-16 19:25:35 +02002710 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2711 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002712
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002713 mutex_lock(&wl->mutex);
2714
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002715 *total &= WL1271_SUPPORTED_FILTERS;
2716 changed &= WL1271_SUPPORTED_FILTERS;
2717
2718 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002719 goto out;
2720
Ido Yariva6208652011-03-01 15:14:41 +02002721 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002722 if (ret < 0)
2723 goto out;
2724
Eliad Peller6e8cd332011-10-10 10:13:13 +02002725 wl12xx_for_each_wlvif(wl, wlvif) {
2726 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2727 if (*total & FIF_ALLMULTI)
2728 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2729 false,
2730 NULL, 0);
2731 else if (fp)
2732 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2733 fp->enabled,
2734 fp->mc_list,
2735 fp->mc_list_length);
2736 if (ret < 0)
2737 goto out_sleep;
2738 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002739 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002740
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002741 /*
2742 * the fw doesn't provide an api to configure the filters. instead,
2743 * the filters configuration is based on the active roles / ROC
2744 * state.
2745 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002746
2747out_sleep:
2748 wl1271_ps_elp_sleep(wl);
2749
2750out:
2751 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002752 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002753}
2754
Eliad Peller170d0e62011-10-05 11:56:06 +02002755static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2756 u8 id, u8 key_type, u8 key_size,
2757 const u8 *key, u8 hlid, u32 tx_seq_32,
2758 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002759{
2760 struct wl1271_ap_key *ap_key;
2761 int i;
2762
2763 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2764
2765 if (key_size > MAX_KEY_SIZE)
2766 return -EINVAL;
2767
2768 /*
2769 * Find next free entry in ap_keys. Also check we are not replacing
2770 * an existing key.
2771 */
2772 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002773 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002774 break;
2775
Eliad Peller170d0e62011-10-05 11:56:06 +02002776 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002777 wl1271_warning("trying to record key replacement");
2778 return -EINVAL;
2779 }
2780 }
2781
2782 if (i == MAX_NUM_KEYS)
2783 return -EBUSY;
2784
2785 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2786 if (!ap_key)
2787 return -ENOMEM;
2788
2789 ap_key->id = id;
2790 ap_key->key_type = key_type;
2791 ap_key->key_size = key_size;
2792 memcpy(ap_key->key, key, key_size);
2793 ap_key->hlid = hlid;
2794 ap_key->tx_seq_32 = tx_seq_32;
2795 ap_key->tx_seq_16 = tx_seq_16;
2796
Eliad Peller170d0e62011-10-05 11:56:06 +02002797 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002798 return 0;
2799}
2800
Eliad Peller170d0e62011-10-05 11:56:06 +02002801static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002802{
2803 int i;
2804
2805 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002806 kfree(wlvif->ap.recorded_keys[i]);
2807 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002808 }
2809}
2810
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002811static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002812{
2813 int i, ret = 0;
2814 struct wl1271_ap_key *key;
2815 bool wep_key_added = false;
2816
2817 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002818 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002819 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002820 break;
2821
Eliad Peller170d0e62011-10-05 11:56:06 +02002822 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002823 hlid = key->hlid;
2824 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002825 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002826
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002827 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002828 key->id, key->key_type,
2829 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002830 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002831 key->tx_seq_16);
2832 if (ret < 0)
2833 goto out;
2834
2835 if (key->key_type == KEY_WEP)
2836 wep_key_added = true;
2837 }
2838
2839 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002840 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002841 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002842 if (ret < 0)
2843 goto out;
2844 }
2845
2846out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002847 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002848 return ret;
2849}
2850
Eliad Peller536129c2011-10-05 11:55:45 +02002851static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2852 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002853 u8 key_size, const u8 *key, u32 tx_seq_32,
2854 u16 tx_seq_16, struct ieee80211_sta *sta)
2855{
2856 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002857 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002858
2859 if (is_ap) {
2860 struct wl1271_station *wl_sta;
2861 u8 hlid;
2862
2863 if (sta) {
2864 wl_sta = (struct wl1271_station *)sta->drv_priv;
2865 hlid = wl_sta->hlid;
2866 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002867 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002868 }
2869
Eliad Peller53d40d02011-10-10 10:13:02 +02002870 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002871 /*
2872 * We do not support removing keys after AP shutdown.
2873 * Pretend we do to make mac80211 happy.
2874 */
2875 if (action != KEY_ADD_OR_REPLACE)
2876 return 0;
2877
Eliad Peller170d0e62011-10-05 11:56:06 +02002878 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002879 key_type, key_size,
2880 key, hlid, tx_seq_32,
2881 tx_seq_16);
2882 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002883 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002884 id, key_type, key_size,
2885 key, hlid, tx_seq_32,
2886 tx_seq_16);
2887 }
2888
2889 if (ret < 0)
2890 return ret;
2891 } else {
2892 const u8 *addr;
2893 static const u8 bcast_addr[ETH_ALEN] = {
2894 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2895 };
2896
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002897 /*
2898 * A STA set to GEM cipher requires 2 tx spare blocks.
2899 * Return to default value when GEM cipher key is removed
2900 */
2901 if (key_type == KEY_GEM) {
2902 if (action == KEY_ADD_OR_REPLACE)
2903 wl->tx_spare_blocks = 2;
2904 else if (action == KEY_REMOVE)
2905 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2906 }
2907
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002908 addr = sta ? sta->addr : bcast_addr;
2909
2910 if (is_zero_ether_addr(addr)) {
2911 /* We dont support TX only encryption */
2912 return -EOPNOTSUPP;
2913 }
2914
2915 /* The wl1271 does not allow to remove unicast keys - they
2916 will be cleared automatically on next CMD_JOIN. Ignore the
2917 request silently, as we dont want the mac80211 to emit
2918 an error message. */
2919 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2920 return 0;
2921
Eliad Peller010d3d32011-08-14 13:17:31 +03002922 /* don't remove key if hlid was already deleted */
2923 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002924 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002925 return 0;
2926
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002927 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002928 id, key_type, key_size,
2929 key, addr, tx_seq_32,
2930 tx_seq_16);
2931 if (ret < 0)
2932 return ret;
2933
2934 /* the default WEP key needs to be configured at least once */
2935 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002936 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002937 wlvif->default_key,
2938 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002939 if (ret < 0)
2940 return ret;
2941 }
2942 }
2943
2944 return 0;
2945}
2946
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002947static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2948 struct ieee80211_vif *vif,
2949 struct ieee80211_sta *sta,
2950 struct ieee80211_key_conf *key_conf)
2951{
2952 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002953 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002954 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002955 u32 tx_seq_32 = 0;
2956 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002957 u8 key_type;
2958
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002959 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2960
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002961 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002962 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002963 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002964 key_conf->keylen, key_conf->flags);
2965 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2966
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002967 mutex_lock(&wl->mutex);
2968
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002969 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2970 ret = -EAGAIN;
2971 goto out_unlock;
2972 }
2973
Ido Yariva6208652011-03-01 15:14:41 +02002974 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002975 if (ret < 0)
2976 goto out_unlock;
2977
Johannes Berg97359d12010-08-10 09:46:38 +02002978 switch (key_conf->cipher) {
2979 case WLAN_CIPHER_SUITE_WEP40:
2980 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002981 key_type = KEY_WEP;
2982
2983 key_conf->hw_key_idx = key_conf->keyidx;
2984 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002985 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002986 key_type = KEY_TKIP;
2987
2988 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002989 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2990 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002991 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002992 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002993 key_type = KEY_AES;
2994
2995 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Eliad Peller48e93e42011-10-10 10:12:58 +02002996 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2997 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002998 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002999 case WL1271_CIPHER_SUITE_GEM:
3000 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02003001 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
3002 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003003 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003004 default:
Johannes Berg97359d12010-08-10 09:46:38 +02003005 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003006
3007 ret = -EOPNOTSUPP;
3008 goto out_sleep;
3009 }
3010
3011 switch (cmd) {
3012 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003013 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003014 key_conf->keyidx, key_type,
3015 key_conf->keylen, key_conf->key,
3016 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003017 if (ret < 0) {
3018 wl1271_error("Could not add or replace key");
3019 goto out_sleep;
3020 }
3021 break;
3022
3023 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003024 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003025 key_conf->keyidx, key_type,
3026 key_conf->keylen, key_conf->key,
3027 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003028 if (ret < 0) {
3029 wl1271_error("Could not remove key");
3030 goto out_sleep;
3031 }
3032 break;
3033
3034 default:
3035 wl1271_error("Unsupported key cmd 0x%x", cmd);
3036 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003037 break;
3038 }
3039
3040out_sleep:
3041 wl1271_ps_elp_sleep(wl);
3042
3043out_unlock:
3044 mutex_unlock(&wl->mutex);
3045
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003046 return ret;
3047}
3048
3049static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003050 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003051 struct cfg80211_scan_request *req)
3052{
3053 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003054 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3055
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003056 int ret;
3057 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003058 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003059
3060 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3061
3062 if (req->n_ssids) {
3063 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003064 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003065 }
3066
3067 mutex_lock(&wl->mutex);
3068
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003069 if (wl->state == WL1271_STATE_OFF) {
3070 /*
3071 * We cannot return -EBUSY here because cfg80211 will expect
3072 * a call to ieee80211_scan_completed if we do - in this case
3073 * there won't be any call.
3074 */
3075 ret = -EAGAIN;
3076 goto out;
3077 }
3078
Ido Yariva6208652011-03-01 15:14:41 +02003079 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003080 if (ret < 0)
3081 goto out;
3082
Eliad Peller251c1772011-08-14 13:17:17 +03003083 /* cancel ROC before scanning */
3084 if (wl12xx_is_roc(wl)) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02003085 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03003086 /* don't allow scanning right now */
3087 ret = -EBUSY;
3088 goto out_sleep;
3089 }
Eliad Peller7edebf52011-10-05 11:55:52 +02003090 wl12xx_croc(wl, wlvif->dev_role_id);
3091 wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003092 }
3093
Eliad Peller784f6942011-10-05 11:55:39 +02003094 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003095out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003096 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003097out:
3098 mutex_unlock(&wl->mutex);
3099
3100 return ret;
3101}
3102
Eliad Peller73ecce32011-06-27 13:06:45 +03003103static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3104 struct ieee80211_vif *vif)
3105{
3106 struct wl1271 *wl = hw->priv;
3107 int ret;
3108
3109 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3110
3111 mutex_lock(&wl->mutex);
3112
3113 if (wl->state == WL1271_STATE_OFF)
3114 goto out;
3115
3116 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3117 goto out;
3118
3119 ret = wl1271_ps_elp_wakeup(wl);
3120 if (ret < 0)
3121 goto out;
3122
3123 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3124 ret = wl1271_scan_stop(wl);
3125 if (ret < 0)
3126 goto out_sleep;
3127 }
3128 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3129 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003130 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003131 wl->scan.req = NULL;
3132 ieee80211_scan_completed(wl->hw, true);
3133
3134out_sleep:
3135 wl1271_ps_elp_sleep(wl);
3136out:
3137 mutex_unlock(&wl->mutex);
3138
3139 cancel_delayed_work_sync(&wl->scan_complete_work);
3140}
3141
Luciano Coelho33c2c062011-05-10 14:46:02 +03003142static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3143 struct ieee80211_vif *vif,
3144 struct cfg80211_sched_scan_request *req,
3145 struct ieee80211_sched_scan_ies *ies)
3146{
3147 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003148 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003149 int ret;
3150
3151 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3152
3153 mutex_lock(&wl->mutex);
3154
3155 ret = wl1271_ps_elp_wakeup(wl);
3156 if (ret < 0)
3157 goto out;
3158
Eliad Peller536129c2011-10-05 11:55:45 +02003159 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003160 if (ret < 0)
3161 goto out_sleep;
3162
Eliad Peller536129c2011-10-05 11:55:45 +02003163 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003164 if (ret < 0)
3165 goto out_sleep;
3166
3167 wl->sched_scanning = true;
3168
3169out_sleep:
3170 wl1271_ps_elp_sleep(wl);
3171out:
3172 mutex_unlock(&wl->mutex);
3173 return ret;
3174}
3175
3176static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3177 struct ieee80211_vif *vif)
3178{
3179 struct wl1271 *wl = hw->priv;
3180 int ret;
3181
3182 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3183
3184 mutex_lock(&wl->mutex);
3185
3186 ret = wl1271_ps_elp_wakeup(wl);
3187 if (ret < 0)
3188 goto out;
3189
3190 wl1271_scan_sched_scan_stop(wl);
3191
3192 wl1271_ps_elp_sleep(wl);
3193out:
3194 mutex_unlock(&wl->mutex);
3195}
3196
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003197static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3198{
3199 struct wl1271 *wl = hw->priv;
3200 int ret = 0;
3201
3202 mutex_lock(&wl->mutex);
3203
3204 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3205 ret = -EAGAIN;
3206 goto out;
3207 }
3208
Ido Yariva6208652011-03-01 15:14:41 +02003209 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003210 if (ret < 0)
3211 goto out;
3212
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003213 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003214 if (ret < 0)
3215 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3216
3217 wl1271_ps_elp_sleep(wl);
3218
3219out:
3220 mutex_unlock(&wl->mutex);
3221
3222 return ret;
3223}
3224
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003225static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3226{
3227 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003228 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003229 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003230
3231 mutex_lock(&wl->mutex);
3232
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003233 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3234 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003235 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003236 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003237
Ido Yariva6208652011-03-01 15:14:41 +02003238 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003239 if (ret < 0)
3240 goto out;
3241
Eliad Peller6e8cd332011-10-10 10:13:13 +02003242 wl12xx_for_each_wlvif(wl, wlvif) {
3243 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3244 if (ret < 0)
3245 wl1271_warning("set rts threshold failed: %d", ret);
3246 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003247 wl1271_ps_elp_sleep(wl);
3248
3249out:
3250 mutex_unlock(&wl->mutex);
3251
3252 return ret;
3253}
3254
Eliad Peller1fe9f162011-10-05 11:55:48 +02003255static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003256 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003257{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003258 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003259 u8 ssid_len;
3260 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3261 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003262
Eliad Peller889cb362011-05-01 09:56:45 +03003263 if (!ptr) {
3264 wl1271_error("No SSID in IEs!");
3265 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003266 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003267
Eliad Peller889cb362011-05-01 09:56:45 +03003268 ssid_len = ptr[1];
3269 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3270 wl1271_error("SSID is too long!");
3271 return -EINVAL;
3272 }
3273
Eliad Peller1fe9f162011-10-05 11:55:48 +02003274 wlvif->ssid_len = ssid_len;
3275 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003276 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003277}
3278
Eliad Pellerd48055d2011-09-15 12:07:04 +03003279static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3280{
3281 int len;
3282 const u8 *next, *end = skb->data + skb->len;
3283 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3284 skb->len - ieoffset);
3285 if (!ie)
3286 return;
3287 len = ie[1] + 2;
3288 next = ie + len;
3289 memmove(ie, next, end - next);
3290 skb_trim(skb, skb->len - len);
3291}
3292
Eliad Peller26b4bf22011-09-15 12:07:05 +03003293static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3294 unsigned int oui, u8 oui_type,
3295 int ieoffset)
3296{
3297 int len;
3298 const u8 *next, *end = skb->data + skb->len;
3299 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3300 skb->data + ieoffset,
3301 skb->len - ieoffset);
3302 if (!ie)
3303 return;
3304 len = ie[1] + 2;
3305 next = ie + len;
3306 memmove(ie, next, end - next);
3307 skb_trim(skb, skb->len - len);
3308}
3309
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003310static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
Eliad Peller1fe9f162011-10-05 11:55:48 +02003311 struct ieee80211_vif *vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003312 u8 *probe_rsp_data,
3313 size_t probe_rsp_len,
3314 u32 rates)
3315{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003316 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3317 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003318 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3319 int ssid_ie_offset, ie_offset, templ_len;
3320 const u8 *ptr;
3321
3322 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003323 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003324 return wl1271_cmd_template_set(wl,
3325 CMD_TEMPL_AP_PROBE_RESPONSE,
3326 probe_rsp_data,
3327 probe_rsp_len, 0,
3328 rates);
3329
3330 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3331 wl1271_error("probe_rsp template too big");
3332 return -EINVAL;
3333 }
3334
3335 /* start searching from IE offset */
3336 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3337
3338 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3339 probe_rsp_len - ie_offset);
3340 if (!ptr) {
3341 wl1271_error("No SSID in beacon!");
3342 return -EINVAL;
3343 }
3344
3345 ssid_ie_offset = ptr - probe_rsp_data;
3346 ptr += (ptr[1] + 2);
3347
3348 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3349
3350 /* insert SSID from bss_conf */
3351 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3352 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3353 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3354 bss_conf->ssid, bss_conf->ssid_len);
3355 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3356
3357 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3358 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3359 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3360
3361 return wl1271_cmd_template_set(wl,
3362 CMD_TEMPL_AP_PROBE_RESPONSE,
3363 probe_rsp_templ,
3364 templ_len, 0,
3365 rates);
3366}
3367
Arik Nemtsove78a2872010-10-16 19:07:21 +02003368static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003369 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003370 struct ieee80211_bss_conf *bss_conf,
3371 u32 changed)
3372{
Eliad Peller0603d892011-10-05 11:55:51 +02003373 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003374 int ret = 0;
3375
3376 if (changed & BSS_CHANGED_ERP_SLOT) {
3377 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003378 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003379 else
Eliad Peller0603d892011-10-05 11:55:51 +02003380 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003381 if (ret < 0) {
3382 wl1271_warning("Set slot time failed %d", ret);
3383 goto out;
3384 }
3385 }
3386
3387 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3388 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003389 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003390 else
Eliad Peller0603d892011-10-05 11:55:51 +02003391 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003392 }
3393
3394 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3395 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003396 ret = wl1271_acx_cts_protect(wl, wlvif,
3397 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003398 else
Eliad Peller0603d892011-10-05 11:55:51 +02003399 ret = wl1271_acx_cts_protect(wl, wlvif,
3400 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003401 if (ret < 0) {
3402 wl1271_warning("Set ctsprotect failed %d", ret);
3403 goto out;
3404 }
3405 }
3406
3407out:
3408 return ret;
3409}
3410
3411static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3412 struct ieee80211_vif *vif,
3413 struct ieee80211_bss_conf *bss_conf,
3414 u32 changed)
3415{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003416 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003417 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003418 int ret = 0;
3419
3420 if ((changed & BSS_CHANGED_BEACON_INT)) {
3421 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3422 bss_conf->beacon_int);
3423
Eliad Peller6a899792011-10-05 11:55:58 +02003424 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003425 }
3426
3427 if ((changed & BSS_CHANGED_BEACON)) {
3428 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003429 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003430 int ieoffset = offsetof(struct ieee80211_mgmt,
3431 u.beacon.variable);
3432 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3433 u16 tmpl_id;
3434
3435 if (!beacon)
3436 goto out;
3437
3438 wl1271_debug(DEBUG_MASTER, "beacon updated");
3439
Eliad Peller1fe9f162011-10-05 11:55:48 +02003440 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003441 if (ret < 0) {
3442 dev_kfree_skb(beacon);
3443 goto out;
3444 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003445 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003446 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3447 CMD_TEMPL_BEACON;
3448 ret = wl1271_cmd_template_set(wl, tmpl_id,
3449 beacon->data,
3450 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003451 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003452 if (ret < 0) {
3453 dev_kfree_skb(beacon);
3454 goto out;
3455 }
3456
Eliad Pellerd48055d2011-09-15 12:07:04 +03003457 /* remove TIM ie from probe response */
3458 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3459
Eliad Peller26b4bf22011-09-15 12:07:05 +03003460 /*
3461 * remove p2p ie from probe response.
3462 * the fw reponds to probe requests that don't include
3463 * the p2p ie. probe requests with p2p ie will be passed,
3464 * and will be responded by the supplicant (the spec
3465 * forbids including the p2p ie when responding to probe
3466 * requests that didn't include it).
3467 */
3468 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3469 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3470
Arik Nemtsove78a2872010-10-16 19:07:21 +02003471 hdr = (struct ieee80211_hdr *) beacon->data;
3472 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3473 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003474 if (is_ap)
Eliad Peller1fe9f162011-10-05 11:55:48 +02003475 ret = wl1271_ap_set_probe_resp_tmpl(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003476 beacon->data,
3477 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003478 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003479 else
3480 ret = wl1271_cmd_template_set(wl,
3481 CMD_TEMPL_PROBE_RESPONSE,
3482 beacon->data,
3483 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003484 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003485 dev_kfree_skb(beacon);
3486 if (ret < 0)
3487 goto out;
3488 }
3489
3490out:
3491 return ret;
3492}
3493
3494/* AP mode changes */
3495static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003496 struct ieee80211_vif *vif,
3497 struct ieee80211_bss_conf *bss_conf,
3498 u32 changed)
3499{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003500 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003501 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003502
Arik Nemtsove78a2872010-10-16 19:07:21 +02003503 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3504 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003505
Eliad Peller87fbcb02011-10-05 11:55:41 +02003506 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003507 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003508 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003509 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003510
Eliad Peller87fbcb02011-10-05 11:55:41 +02003511 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003512 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003513 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003514 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003515 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003516
Eliad Peller784f6942011-10-05 11:55:39 +02003517 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003518 if (ret < 0)
3519 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003520 }
3521
Arik Nemtsove78a2872010-10-16 19:07:21 +02003522 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3523 if (ret < 0)
3524 goto out;
3525
3526 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3527 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003528 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003529 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003530 if (ret < 0)
3531 goto out;
3532
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003533 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003534 if (ret < 0)
3535 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003536
Eliad Peller53d40d02011-10-10 10:13:02 +02003537 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003538 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003539 }
3540 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003541 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003542 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003543 if (ret < 0)
3544 goto out;
3545
Eliad Peller53d40d02011-10-10 10:13:02 +02003546 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003547 wl1271_debug(DEBUG_AP, "stopped AP");
3548 }
3549 }
3550 }
3551
Eliad Peller0603d892011-10-05 11:55:51 +02003552 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003553 if (ret < 0)
3554 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003555
3556 /* Handle HT information change */
3557 if ((changed & BSS_CHANGED_HT) &&
3558 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003559 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003560 bss_conf->ht_operation_mode);
3561 if (ret < 0) {
3562 wl1271_warning("Set ht information failed %d", ret);
3563 goto out;
3564 }
3565 }
3566
Arik Nemtsove78a2872010-10-16 19:07:21 +02003567out:
3568 return;
3569}
3570
3571/* STA/IBSS mode changes */
3572static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3573 struct ieee80211_vif *vif,
3574 struct ieee80211_bss_conf *bss_conf,
3575 u32 changed)
3576{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003577 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003578 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003579 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003580 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003581 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003582 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003583 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003584 bool sta_exists = false;
3585 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003586
3587 if (is_ibss) {
3588 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3589 changed);
3590 if (ret < 0)
3591 goto out;
3592 }
3593
Eliad Peller227e81e2011-08-14 13:17:26 +03003594 if (changed & BSS_CHANGED_IBSS) {
3595 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003596 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003597 ibss_joined = true;
3598 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003599 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3600 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003601 wl1271_unjoin(wl, wlvif);
Eliad Peller7edebf52011-10-05 11:55:52 +02003602 wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller1b92f152011-10-10 10:13:09 +02003603 wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
Eliad Peller227e81e2011-08-14 13:17:26 +03003604 }
3605 }
3606 }
3607
3608 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003609 do_join = true;
3610
3611 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003612 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003613 do_join = true;
3614
Eliad Peller227e81e2011-08-14 13:17:26 +03003615 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003616 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3617 bss_conf->enable_beacon ? "enabled" : "disabled");
3618
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003619 do_join = true;
3620 }
3621
Arik Nemtsove78a2872010-10-16 19:07:21 +02003622 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003623 bool enable = false;
3624 if (bss_conf->cqm_rssi_thold)
3625 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003626 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003627 bss_conf->cqm_rssi_thold,
3628 bss_conf->cqm_rssi_hyst);
3629 if (ret < 0)
3630 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003631 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003632 }
3633
Eliad Pellercdf09492011-10-05 11:55:44 +02003634 if (changed & BSS_CHANGED_BSSID)
3635 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003636 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003637 if (ret < 0)
3638 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003639
Eliad Peller784f6942011-10-05 11:55:39 +02003640 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003641 if (ret < 0)
3642 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003643
Eliad Pellerfa287b82010-12-26 09:27:50 +01003644 /* Need to update the BSSID (for filtering etc) */
3645 do_join = true;
3646 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003647
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003648 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3649 rcu_read_lock();
3650 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3651 if (!sta)
3652 goto sta_not_found;
3653
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003654 /* save the supp_rates of the ap */
3655 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3656 if (sta->ht_cap.ht_supported)
3657 sta_rate_set |=
3658 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003659 sta_ht_cap = sta->ht_cap;
3660 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003661
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003662sta_not_found:
3663 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003664 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003665
Arik Nemtsove78a2872010-10-16 19:07:21 +02003666 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003667 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003668 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003669 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003670 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003671 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003672
Eliad Peller74ec8392011-10-05 11:56:02 +02003673 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003674
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003675 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003676 * use basic rates from AP, and determine lowest rate
3677 * to use with control frames.
3678 */
3679 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003680 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003681 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003682 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003683 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003684 wl1271_tx_min_rate_get(wl,
3685 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003686 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003687 wlvif->rate_set =
3688 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003689 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003690 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003691 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003692 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003693 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003694
3695 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003696 * with wl1271, we don't need to update the
3697 * beacon_int and dtim_period, because the firmware
3698 * updates it by itself when the first beacon is
3699 * received after a join.
3700 */
Eliad Peller6840e372011-10-05 11:55:50 +02003701 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003702 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003703 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003704
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003705 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003706 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003707 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003708 dev_kfree_skb(wlvif->probereq);
3709 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003710 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003711 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003712 ieoffset = offsetof(struct ieee80211_mgmt,
3713 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003714 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003715
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003716 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003717 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003718 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003719 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003720 } else {
3721 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003722 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003723 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3724 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003725 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003726 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3727 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003728 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003729
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003730 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003731 dev_kfree_skb(wlvif->probereq);
3732 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003733
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003734 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003735 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003736
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003737 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003738 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003739 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003740 wl1271_tx_min_rate_get(wl,
3741 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003742 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003743 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003744 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003745
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003746 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003747 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003748
3749 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003750 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003751 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003752 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003753
3754 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003755 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003756 u32 conf_flags = wl->hw->conf.flags;
3757 /*
3758 * we might have to disable roc, if there was
3759 * no IF_OPER_UP notification.
3760 */
3761 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003762 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003763 if (ret < 0)
3764 goto out;
3765 }
3766 /*
3767 * (we also need to disable roc in case of
3768 * roaming on the same channel. until we will
3769 * have a better flow...)
3770 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003771 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3772 ret = wl12xx_croc(wl,
3773 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003774 if (ret < 0)
3775 goto out;
3776 }
3777
Eliad Peller0603d892011-10-05 11:55:51 +02003778 wl1271_unjoin(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003779 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02003780 wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller1b92f152011-10-10 10:13:09 +02003781 wl12xx_roc(wl, wlvif,
3782 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003783 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003784 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003785 }
3786 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003787
Eliad Pellerd192d262011-05-24 14:33:08 +03003788 if (changed & BSS_CHANGED_IBSS) {
3789 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3790 bss_conf->ibss_joined);
3791
3792 if (bss_conf->ibss_joined) {
3793 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003794 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003795 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003796 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003797 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003798 wl1271_tx_min_rate_get(wl,
3799 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003800
Shahar Levi06b660e2011-09-05 13:54:36 +03003801 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003802 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3803 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003804 if (ret < 0)
3805 goto out;
3806 }
3807 }
3808
Eliad Peller0603d892011-10-05 11:55:51 +02003809 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003810 if (ret < 0)
3811 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003812
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003813 if (changed & BSS_CHANGED_ARP_FILTER) {
3814 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003815 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003816
Eliad Pellerc5312772010-12-09 11:31:27 +02003817 if (bss_conf->arp_addr_cnt == 1 &&
3818 bss_conf->arp_filter_enabled) {
3819 /*
3820 * The template should have been configured only upon
3821 * association. however, it seems that the correct ip
3822 * isn't being set (when sending), so we have to
3823 * reconfigure the template upon every ip change.
3824 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003825 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003826 if (ret < 0) {
3827 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003828 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003829 }
3830
Eliad Peller0603d892011-10-05 11:55:51 +02003831 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003832 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003833 addr);
3834 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003835 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003836
3837 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003838 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003839 }
3840
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003841 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003842 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003843 if (ret < 0) {
3844 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003845 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003846 }
Eliad Peller251c1772011-08-14 13:17:17 +03003847
3848 /* ROC until connected (after EAPOL exchange) */
3849 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003850 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003851 if (ret < 0)
3852 goto out;
3853
Eliad Pellerba8447f2011-10-10 10:13:00 +02003854 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003855 ieee80211_get_operstate(vif));
3856 }
3857 /*
3858 * stop device role if started (we might already be in
3859 * STA role). TODO: make it better.
3860 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003861 if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3862 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003863 if (ret < 0)
3864 goto out;
3865
Eliad Peller7edebf52011-10-05 11:55:52 +02003866 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003867 if (ret < 0)
3868 goto out;
3869 }
Eliad Peller05dba352011-08-23 16:37:01 +03003870
3871 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003872 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3873 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003874 enum wl1271_cmd_ps_mode mode;
3875
3876 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003877 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003878 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003879 true);
3880 if (ret < 0)
3881 goto out;
3882 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003883 }
3884
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003885 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003886 if (sta_exists) {
3887 if ((changed & BSS_CHANGED_HT) &&
3888 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003889 ret = wl1271_acx_set_ht_capabilities(wl,
3890 &sta_ht_cap,
3891 true,
Eliad Peller154da672011-10-05 11:55:53 +02003892 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003893 if (ret < 0) {
3894 wl1271_warning("Set ht cap true failed %d",
3895 ret);
3896 goto out;
3897 }
3898 }
3899 /* handle new association without HT and disassociation */
3900 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003901 ret = wl1271_acx_set_ht_capabilities(wl,
3902 &sta_ht_cap,
3903 false,
Eliad Peller154da672011-10-05 11:55:53 +02003904 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003905 if (ret < 0) {
3906 wl1271_warning("Set ht cap false failed %d",
3907 ret);
3908 goto out;
3909 }
3910 }
3911 }
3912
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003913 /* Handle HT information change. Done after join. */
3914 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003915 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003916 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003917 bss_conf->ht_operation_mode);
3918 if (ret < 0) {
3919 wl1271_warning("Set ht information failed %d", ret);
3920 goto out;
3921 }
3922 }
3923
Arik Nemtsove78a2872010-10-16 19:07:21 +02003924out:
3925 return;
3926}
3927
3928static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3929 struct ieee80211_vif *vif,
3930 struct ieee80211_bss_conf *bss_conf,
3931 u32 changed)
3932{
3933 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003934 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3935 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003936 int ret;
3937
3938 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3939 (int)changed);
3940
3941 mutex_lock(&wl->mutex);
3942
3943 if (unlikely(wl->state == WL1271_STATE_OFF))
3944 goto out;
3945
Eliad Peller10c8cd02011-10-10 10:13:06 +02003946 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3947 goto out;
3948
Ido Yariva6208652011-03-01 15:14:41 +02003949 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003950 if (ret < 0)
3951 goto out;
3952
3953 if (is_ap)
3954 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3955 else
3956 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3957
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003958 wl1271_ps_elp_sleep(wl);
3959
3960out:
3961 mutex_unlock(&wl->mutex);
3962}
3963
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003964static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3965 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003966 const struct ieee80211_tx_queue_params *params)
3967{
3968 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003969 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003970 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003971 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003972
3973 mutex_lock(&wl->mutex);
3974
3975 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3976
Kalle Valo4695dc92010-03-18 12:26:38 +02003977 if (params->uapsd)
3978 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3979 else
3980 ps_scheme = CONF_PS_SCHEME_LEGACY;
3981
Arik Nemtsov488fc542010-10-16 20:33:45 +02003982 if (wl->state == WL1271_STATE_OFF) {
3983 /*
3984 * If the state is off, the parameters will be recorded and
3985 * configured on init. This happens in AP-mode.
3986 */
3987 struct conf_tx_ac_category *conf_ac =
3988 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3989 struct conf_tx_tid *conf_tid =
3990 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3991
3992 conf_ac->ac = wl1271_tx_get_queue(queue);
3993 conf_ac->cw_min = (u8)params->cw_min;
3994 conf_ac->cw_max = params->cw_max;
3995 conf_ac->aifsn = params->aifs;
3996 conf_ac->tx_op_limit = params->txop << 5;
3997
3998 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3999 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
4000 conf_tid->tsid = wl1271_tx_get_queue(queue);
4001 conf_tid->ps_scheme = ps_scheme;
4002 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
4003 conf_tid->apsd_conf[0] = 0;
4004 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004005 goto out;
4006 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02004007
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004008 ret = wl1271_ps_elp_wakeup(wl);
4009 if (ret < 0)
4010 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004011
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004012 /*
4013 * the txop is confed in units of 32us by the mac80211,
4014 * we need us
4015 */
Eliad Peller0603d892011-10-05 11:55:51 +02004016 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004017 params->cw_min, params->cw_max,
4018 params->aifs, params->txop << 5);
4019 if (ret < 0)
4020 goto out_sleep;
4021
Eliad Peller0603d892011-10-05 11:55:51 +02004022 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004023 CONF_CHANNEL_TYPE_EDCF,
4024 wl1271_tx_get_queue(queue),
4025 ps_scheme, CONF_ACK_POLICY_LEGACY,
4026 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004027
4028out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004029 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004030
4031out:
4032 mutex_unlock(&wl->mutex);
4033
4034 return ret;
4035}
4036
Eliad Peller37a41b42011-09-21 14:06:11 +03004037static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4038 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004039{
4040
4041 struct wl1271 *wl = hw->priv;
4042 u64 mactime = ULLONG_MAX;
4043 int ret;
4044
4045 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4046
4047 mutex_lock(&wl->mutex);
4048
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004049 if (unlikely(wl->state == WL1271_STATE_OFF))
4050 goto out;
4051
Ido Yariva6208652011-03-01 15:14:41 +02004052 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004053 if (ret < 0)
4054 goto out;
4055
4056 ret = wl1271_acx_tsf_info(wl, &mactime);
4057 if (ret < 0)
4058 goto out_sleep;
4059
4060out_sleep:
4061 wl1271_ps_elp_sleep(wl);
4062
4063out:
4064 mutex_unlock(&wl->mutex);
4065 return mactime;
4066}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004067
John W. Linvilleece550d2010-07-28 16:41:06 -04004068static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4069 struct survey_info *survey)
4070{
4071 struct wl1271 *wl = hw->priv;
4072 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004073
John W. Linvilleece550d2010-07-28 16:41:06 -04004074 if (idx != 0)
4075 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004076
John W. Linvilleece550d2010-07-28 16:41:06 -04004077 survey->channel = conf->channel;
4078 survey->filled = SURVEY_INFO_NOISE_DBM;
4079 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004080
John W. Linvilleece550d2010-07-28 16:41:06 -04004081 return 0;
4082}
4083
Arik Nemtsov409622e2011-02-23 00:22:29 +02004084static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004085 struct wl12xx_vif *wlvif,
4086 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004087{
4088 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004089 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004090
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004091
4092 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004093 wl1271_warning("could not allocate HLID - too much stations");
4094 return -EBUSY;
4095 }
4096
4097 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004098 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4099 if (ret < 0) {
4100 wl1271_warning("could not allocate HLID - too many links");
4101 return -EBUSY;
4102 }
4103
4104 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004105 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004106 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004107 return 0;
4108}
4109
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004110void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004111{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004112 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004113 return;
4114
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004115 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004116 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004117 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004118 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004119 __clear_bit(hlid, &wl->ap_ps_map);
4120 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004121 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004122 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004123}
4124
4125static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4126 struct ieee80211_vif *vif,
4127 struct ieee80211_sta *sta)
4128{
4129 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004130 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004131 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004132 int ret = 0;
4133 u8 hlid;
4134
4135 mutex_lock(&wl->mutex);
4136
4137 if (unlikely(wl->state == WL1271_STATE_OFF))
4138 goto out;
4139
Eliad Peller536129c2011-10-05 11:55:45 +02004140 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004141 goto out;
4142
4143 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4144
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004145 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004146 if (ret < 0)
4147 goto out;
4148
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004149 wl_sta = (struct wl1271_station *)sta->drv_priv;
4150 hlid = wl_sta->hlid;
4151
Ido Yariva6208652011-03-01 15:14:41 +02004152 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004153 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004154 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004155
Eliad Peller1b92f152011-10-10 10:13:09 +02004156 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004157 if (ret < 0)
4158 goto out_sleep;
4159
Eliad Pellerb67476e2011-08-14 13:17:23 +03004160 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4161 if (ret < 0)
4162 goto out_sleep;
4163
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004164 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4165 if (ret < 0)
4166 goto out_sleep;
4167
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004168out_sleep:
4169 wl1271_ps_elp_sleep(wl);
4170
Arik Nemtsov409622e2011-02-23 00:22:29 +02004171out_free_sta:
4172 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004173 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004174
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004175out:
4176 mutex_unlock(&wl->mutex);
4177 return ret;
4178}
4179
4180static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4181 struct ieee80211_vif *vif,
4182 struct ieee80211_sta *sta)
4183{
4184 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004185 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004186 struct wl1271_station *wl_sta;
4187 int ret = 0, id;
4188
4189 mutex_lock(&wl->mutex);
4190
4191 if (unlikely(wl->state == WL1271_STATE_OFF))
4192 goto out;
4193
Eliad Peller536129c2011-10-05 11:55:45 +02004194 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004195 goto out;
4196
4197 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4198
4199 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004200 id = wl_sta->hlid;
4201 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004202 goto out;
4203
Ido Yariva6208652011-03-01 15:14:41 +02004204 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004205 if (ret < 0)
4206 goto out;
4207
Eliad Pellerc690ec82011-08-14 13:17:07 +03004208 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004209 if (ret < 0)
4210 goto out_sleep;
4211
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004212 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004213
4214out_sleep:
4215 wl1271_ps_elp_sleep(wl);
4216
4217out:
4218 mutex_unlock(&wl->mutex);
4219 return ret;
4220}
4221
Luciano Coelho4623ec72011-03-21 19:26:41 +02004222static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4223 struct ieee80211_vif *vif,
4224 enum ieee80211_ampdu_mlme_action action,
4225 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4226 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004227{
4228 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004229 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004230 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004231 u8 hlid, *ba_bitmap;
4232
4233 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4234 tid);
4235
4236 /* sanity check - the fields in FW are only 8bits wide */
4237 if (WARN_ON(tid > 0xFF))
4238 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004239
4240 mutex_lock(&wl->mutex);
4241
4242 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4243 ret = -EAGAIN;
4244 goto out;
4245 }
4246
Eliad Peller536129c2011-10-05 11:55:45 +02004247 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004248 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004249 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004250 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004251 struct wl1271_station *wl_sta;
4252
4253 wl_sta = (struct wl1271_station *)sta->drv_priv;
4254 hlid = wl_sta->hlid;
4255 ba_bitmap = &wl->links[hlid].ba_bitmap;
4256 } else {
4257 ret = -EINVAL;
4258 goto out;
4259 }
4260
Ido Yariva6208652011-03-01 15:14:41 +02004261 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004262 if (ret < 0)
4263 goto out;
4264
Shahar Levi70559a02011-05-22 16:10:22 +03004265 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4266 tid, action);
4267
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004268 switch (action) {
4269 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004270 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004271 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004272 break;
4273 }
4274
4275 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4276 ret = -EBUSY;
4277 wl1271_error("exceeded max RX BA sessions");
4278 break;
4279 }
4280
4281 if (*ba_bitmap & BIT(tid)) {
4282 ret = -EINVAL;
4283 wl1271_error("cannot enable RX BA session on active "
4284 "tid: %d", tid);
4285 break;
4286 }
4287
4288 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4289 hlid);
4290 if (!ret) {
4291 *ba_bitmap |= BIT(tid);
4292 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004293 }
4294 break;
4295
4296 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004297 if (!(*ba_bitmap & BIT(tid))) {
4298 ret = -EINVAL;
4299 wl1271_error("no active RX BA session on tid: %d",
4300 tid);
4301 break;
4302 }
4303
4304 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4305 hlid);
4306 if (!ret) {
4307 *ba_bitmap &= ~BIT(tid);
4308 wl->ba_rx_session_count--;
4309 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004310 break;
4311
4312 /*
4313 * The BA initiator session management in FW independently.
4314 * Falling break here on purpose for all TX APDU commands.
4315 */
4316 case IEEE80211_AMPDU_TX_START:
4317 case IEEE80211_AMPDU_TX_STOP:
4318 case IEEE80211_AMPDU_TX_OPERATIONAL:
4319 ret = -EINVAL;
4320 break;
4321
4322 default:
4323 wl1271_error("Incorrect ampdu action id=%x\n", action);
4324 ret = -EINVAL;
4325 }
4326
4327 wl1271_ps_elp_sleep(wl);
4328
4329out:
4330 mutex_unlock(&wl->mutex);
4331
4332 return ret;
4333}
4334
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004335static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4336 struct ieee80211_vif *vif,
4337 const struct cfg80211_bitrate_mask *mask)
4338{
Eliad Peller83587502011-10-10 10:12:53 +02004339 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004340 struct wl1271 *wl = hw->priv;
4341 int i;
4342
4343 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4344 mask->control[NL80211_BAND_2GHZ].legacy,
4345 mask->control[NL80211_BAND_5GHZ].legacy);
4346
4347 mutex_lock(&wl->mutex);
4348
4349 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004350 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004351 wl1271_tx_enabled_rates_get(wl,
4352 mask->control[i].legacy,
4353 i);
4354 mutex_unlock(&wl->mutex);
4355
4356 return 0;
4357}
4358
Shahar Levi6d158ff2011-09-08 13:01:33 +03004359static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4360 struct ieee80211_channel_switch *ch_switch)
4361{
4362 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004363 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004364 int ret;
4365
4366 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4367
4368 mutex_lock(&wl->mutex);
4369
4370 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004371 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4372 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4373 ieee80211_chswitch_done(vif, false);
4374 }
4375 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004376 }
4377
4378 ret = wl1271_ps_elp_wakeup(wl);
4379 if (ret < 0)
4380 goto out;
4381
Eliad Peller52630c52011-10-10 10:13:08 +02004382 /* TODO: change mac80211 to pass vif as param */
4383 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4384 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004385
Eliad Peller52630c52011-10-10 10:13:08 +02004386 if (!ret)
4387 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4388 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004389
4390 wl1271_ps_elp_sleep(wl);
4391
4392out:
4393 mutex_unlock(&wl->mutex);
4394}
4395
Arik Nemtsov33437892011-04-26 23:35:39 +03004396static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4397{
4398 struct wl1271 *wl = hw->priv;
4399 bool ret = false;
4400
4401 mutex_lock(&wl->mutex);
4402
4403 if (unlikely(wl->state == WL1271_STATE_OFF))
4404 goto out;
4405
4406 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004407 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004408out:
4409 mutex_unlock(&wl->mutex);
4410
4411 return ret;
4412}
4413
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004414/* can't be const, mac80211 writes to this */
4415static struct ieee80211_rate wl1271_rates[] = {
4416 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004417 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4418 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004419 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004420 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4421 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004422 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4423 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004424 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4425 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004426 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4427 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004428 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4429 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004430 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4431 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004432 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4433 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004434 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004435 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4436 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004437 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004438 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4439 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004440 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004441 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4442 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004443 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004444 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4445 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004446 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004447 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4448 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004449 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004450 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4451 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004452 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004453 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4454 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004455};
4456
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004457/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004458static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004459 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004460 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004461 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4462 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4463 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004464 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004465 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4466 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4467 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004468 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004469 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4470 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4471 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004472 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004473};
4474
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004475/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004476static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004477 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004478 7, /* CONF_HW_RXTX_RATE_MCS7 */
4479 6, /* CONF_HW_RXTX_RATE_MCS6 */
4480 5, /* CONF_HW_RXTX_RATE_MCS5 */
4481 4, /* CONF_HW_RXTX_RATE_MCS4 */
4482 3, /* CONF_HW_RXTX_RATE_MCS3 */
4483 2, /* CONF_HW_RXTX_RATE_MCS2 */
4484 1, /* CONF_HW_RXTX_RATE_MCS1 */
4485 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004486
4487 11, /* CONF_HW_RXTX_RATE_54 */
4488 10, /* CONF_HW_RXTX_RATE_48 */
4489 9, /* CONF_HW_RXTX_RATE_36 */
4490 8, /* CONF_HW_RXTX_RATE_24 */
4491
4492 /* TI-specific rate */
4493 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4494
4495 7, /* CONF_HW_RXTX_RATE_18 */
4496 6, /* CONF_HW_RXTX_RATE_12 */
4497 3, /* CONF_HW_RXTX_RATE_11 */
4498 5, /* CONF_HW_RXTX_RATE_9 */
4499 4, /* CONF_HW_RXTX_RATE_6 */
4500 2, /* CONF_HW_RXTX_RATE_5_5 */
4501 1, /* CONF_HW_RXTX_RATE_2 */
4502 0 /* CONF_HW_RXTX_RATE_1 */
4503};
4504
Shahar Levie8b03a22010-10-13 16:09:39 +02004505/* 11n STA capabilities */
4506#define HW_RX_HIGHEST_RATE 72
4507
Shahar Levi00d20102010-11-08 11:20:10 +00004508#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004509 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4510 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004511 .ht_supported = true, \
4512 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4513 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4514 .mcs = { \
4515 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4516 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4517 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4518 }, \
4519}
4520
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004521/* can't be const, mac80211 writes to this */
4522static struct ieee80211_supported_band wl1271_band_2ghz = {
4523 .channels = wl1271_channels,
4524 .n_channels = ARRAY_SIZE(wl1271_channels),
4525 .bitrates = wl1271_rates,
4526 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004527 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004528};
4529
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004530/* 5 GHz data rates for WL1273 */
4531static struct ieee80211_rate wl1271_rates_5ghz[] = {
4532 { .bitrate = 60,
4533 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4534 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4535 { .bitrate = 90,
4536 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4537 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4538 { .bitrate = 120,
4539 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4540 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4541 { .bitrate = 180,
4542 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4543 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4544 { .bitrate = 240,
4545 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4546 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4547 { .bitrate = 360,
4548 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4549 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4550 { .bitrate = 480,
4551 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4552 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4553 { .bitrate = 540,
4554 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4555 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4556};
4557
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004558/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004559static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004560 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4561 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4562 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4563 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4564 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4565 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4566 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4567 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4568 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4569 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4570 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4571 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4572 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4573 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4574 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4575 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4576 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4577 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4578 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4579 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4580 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4581 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4582 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4583 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4584 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4585 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4586 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4587 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4588 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4589 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4590 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4591 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4592 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4593 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004594};
4595
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004596/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004597static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004598 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004599 7, /* CONF_HW_RXTX_RATE_MCS7 */
4600 6, /* CONF_HW_RXTX_RATE_MCS6 */
4601 5, /* CONF_HW_RXTX_RATE_MCS5 */
4602 4, /* CONF_HW_RXTX_RATE_MCS4 */
4603 3, /* CONF_HW_RXTX_RATE_MCS3 */
4604 2, /* CONF_HW_RXTX_RATE_MCS2 */
4605 1, /* CONF_HW_RXTX_RATE_MCS1 */
4606 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004607
4608 7, /* CONF_HW_RXTX_RATE_54 */
4609 6, /* CONF_HW_RXTX_RATE_48 */
4610 5, /* CONF_HW_RXTX_RATE_36 */
4611 4, /* CONF_HW_RXTX_RATE_24 */
4612
4613 /* TI-specific rate */
4614 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4615
4616 3, /* CONF_HW_RXTX_RATE_18 */
4617 2, /* CONF_HW_RXTX_RATE_12 */
4618 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4619 1, /* CONF_HW_RXTX_RATE_9 */
4620 0, /* CONF_HW_RXTX_RATE_6 */
4621 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4622 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4623 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4624};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004625
4626static struct ieee80211_supported_band wl1271_band_5ghz = {
4627 .channels = wl1271_channels_5ghz,
4628 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4629 .bitrates = wl1271_rates_5ghz,
4630 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004631 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004632};
4633
Tobias Klausera0ea9492010-05-20 10:38:11 +02004634static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004635 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4636 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4637};
4638
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004639static const struct ieee80211_ops wl1271_ops = {
4640 .start = wl1271_op_start,
4641 .stop = wl1271_op_stop,
4642 .add_interface = wl1271_op_add_interface,
4643 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004644#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004645 .suspend = wl1271_op_suspend,
4646 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004647#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004648 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004649 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004650 .configure_filter = wl1271_op_configure_filter,
4651 .tx = wl1271_op_tx,
4652 .set_key = wl1271_op_set_key,
4653 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004654 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004655 .sched_scan_start = wl1271_op_sched_scan_start,
4656 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004657 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004658 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004659 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004660 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004661 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004662 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004663 .sta_add = wl1271_op_sta_add,
4664 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004665 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004666 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004667 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004668 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004669 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004670};
4671
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004672
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004673u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004674{
4675 u8 idx;
4676
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004677 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004678
4679 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4680 wl1271_error("Illegal RX rate from HW: %d", rate);
4681 return 0;
4682 }
4683
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004684 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004685 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4686 wl1271_error("Unsupported RX rate from HW: %d", rate);
4687 return 0;
4688 }
4689
4690 return idx;
4691}
4692
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004693static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4694 struct device_attribute *attr,
4695 char *buf)
4696{
4697 struct wl1271 *wl = dev_get_drvdata(dev);
4698 ssize_t len;
4699
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004700 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004701
4702 mutex_lock(&wl->mutex);
4703 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4704 wl->sg_enabled);
4705 mutex_unlock(&wl->mutex);
4706
4707 return len;
4708
4709}
4710
4711static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4712 struct device_attribute *attr,
4713 const char *buf, size_t count)
4714{
4715 struct wl1271 *wl = dev_get_drvdata(dev);
4716 unsigned long res;
4717 int ret;
4718
Luciano Coelho6277ed62011-04-01 17:49:54 +03004719 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004720 if (ret < 0) {
4721 wl1271_warning("incorrect value written to bt_coex_mode");
4722 return count;
4723 }
4724
4725 mutex_lock(&wl->mutex);
4726
4727 res = !!res;
4728
4729 if (res == wl->sg_enabled)
4730 goto out;
4731
4732 wl->sg_enabled = res;
4733
4734 if (wl->state == WL1271_STATE_OFF)
4735 goto out;
4736
Ido Yariva6208652011-03-01 15:14:41 +02004737 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004738 if (ret < 0)
4739 goto out;
4740
4741 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4742 wl1271_ps_elp_sleep(wl);
4743
4744 out:
4745 mutex_unlock(&wl->mutex);
4746 return count;
4747}
4748
4749static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4750 wl1271_sysfs_show_bt_coex_state,
4751 wl1271_sysfs_store_bt_coex_state);
4752
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004753static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4754 struct device_attribute *attr,
4755 char *buf)
4756{
4757 struct wl1271 *wl = dev_get_drvdata(dev);
4758 ssize_t len;
4759
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004760 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004761
4762 mutex_lock(&wl->mutex);
4763 if (wl->hw_pg_ver >= 0)
4764 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4765 else
4766 len = snprintf(buf, len, "n/a\n");
4767 mutex_unlock(&wl->mutex);
4768
4769 return len;
4770}
4771
Gery Kahn6f07b722011-07-18 14:21:49 +03004772static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004773 wl1271_sysfs_show_hw_pg_ver, NULL);
4774
Ido Yariv95dac04f2011-06-06 14:57:06 +03004775static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4776 struct bin_attribute *bin_attr,
4777 char *buffer, loff_t pos, size_t count)
4778{
4779 struct device *dev = container_of(kobj, struct device, kobj);
4780 struct wl1271 *wl = dev_get_drvdata(dev);
4781 ssize_t len;
4782 int ret;
4783
4784 ret = mutex_lock_interruptible(&wl->mutex);
4785 if (ret < 0)
4786 return -ERESTARTSYS;
4787
4788 /* Let only one thread read the log at a time, blocking others */
4789 while (wl->fwlog_size == 0) {
4790 DEFINE_WAIT(wait);
4791
4792 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4793 &wait,
4794 TASK_INTERRUPTIBLE);
4795
4796 if (wl->fwlog_size != 0) {
4797 finish_wait(&wl->fwlog_waitq, &wait);
4798 break;
4799 }
4800
4801 mutex_unlock(&wl->mutex);
4802
4803 schedule();
4804 finish_wait(&wl->fwlog_waitq, &wait);
4805
4806 if (signal_pending(current))
4807 return -ERESTARTSYS;
4808
4809 ret = mutex_lock_interruptible(&wl->mutex);
4810 if (ret < 0)
4811 return -ERESTARTSYS;
4812 }
4813
4814 /* Check if the fwlog is still valid */
4815 if (wl->fwlog_size < 0) {
4816 mutex_unlock(&wl->mutex);
4817 return 0;
4818 }
4819
4820 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4821 len = min(count, (size_t)wl->fwlog_size);
4822 wl->fwlog_size -= len;
4823 memcpy(buffer, wl->fwlog, len);
4824
4825 /* Make room for new messages */
4826 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4827
4828 mutex_unlock(&wl->mutex);
4829
4830 return len;
4831}
4832
4833static struct bin_attribute fwlog_attr = {
4834 .attr = {.name = "fwlog", .mode = S_IRUSR},
4835 .read = wl1271_sysfs_read_fwlog,
4836};
4837
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004838static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004839{
4840 int ret;
4841
4842 if (wl->mac80211_registered)
4843 return 0;
4844
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004845 ret = wl1271_fetch_nvs(wl);
4846 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004847 /* NOTE: The wl->nvs->nvs element must be first, in
4848 * order to simplify the casting, we assume it is at
4849 * the beginning of the wl->nvs structure.
4850 */
4851 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004852
4853 wl->mac_addr[0] = nvs_ptr[11];
4854 wl->mac_addr[1] = nvs_ptr[10];
4855 wl->mac_addr[2] = nvs_ptr[6];
4856 wl->mac_addr[3] = nvs_ptr[5];
4857 wl->mac_addr[4] = nvs_ptr[4];
4858 wl->mac_addr[5] = nvs_ptr[3];
4859 }
4860
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004861 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4862
4863 ret = ieee80211_register_hw(wl->hw);
4864 if (ret < 0) {
4865 wl1271_error("unable to register mac80211 hw: %d", ret);
4866 return ret;
4867 }
4868
4869 wl->mac80211_registered = true;
4870
Eliad Pellerd60080a2010-11-24 12:53:16 +02004871 wl1271_debugfs_init(wl);
4872
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004873 register_netdevice_notifier(&wl1271_dev_notifier);
4874
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004875 wl1271_notice("loaded");
4876
4877 return 0;
4878}
4879
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004880static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004881{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004882 if (wl->state == WL1271_STATE_PLT)
4883 __wl1271_plt_stop(wl);
4884
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004885 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004886 ieee80211_unregister_hw(wl->hw);
4887 wl->mac80211_registered = false;
4888
4889}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004890
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004891static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004892{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004893 static const u32 cipher_suites[] = {
4894 WLAN_CIPHER_SUITE_WEP40,
4895 WLAN_CIPHER_SUITE_WEP104,
4896 WLAN_CIPHER_SUITE_TKIP,
4897 WLAN_CIPHER_SUITE_CCMP,
4898 WL1271_CIPHER_SUITE_GEM,
4899 };
4900
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004901 /* The tx descriptor buffer and the TKIP space. */
4902 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4903 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004904
4905 /* unit us */
4906 /* FIXME: find a proper value */
4907 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004908 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004909
4910 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004911 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004912 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004913 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004914 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004915 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004916 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004917 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004918 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004919 IEEE80211_HW_AP_LINK_PS |
4920 IEEE80211_HW_AMPDU_AGGREGATION |
4921 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004922
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004923 wl->hw->wiphy->cipher_suites = cipher_suites;
4924 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4925
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004926 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004927 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4928 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004929 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004930 wl->hw->wiphy->max_sched_scan_ssids = 16;
4931 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004932 /*
4933 * Maximum length of elements in scanning probe request templates
4934 * should be the maximum length possible for a template, without
4935 * the IEEE80211 header of the template
4936 */
Eliad Peller154037d2011-08-14 13:17:12 +03004937 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004938 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004939
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004940 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4941 sizeof(struct ieee80211_header);
4942
Eliad Peller1ec23f72011-08-25 14:26:54 +03004943 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4944
Luciano Coelho4a31c112011-03-21 23:16:14 +02004945 /* make sure all our channels fit in the scanned_ch bitmask */
4946 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4947 ARRAY_SIZE(wl1271_channels_5ghz) >
4948 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004949 /*
4950 * We keep local copies of the band structs because we need to
4951 * modify them on a per-device basis.
4952 */
4953 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4954 sizeof(wl1271_band_2ghz));
4955 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4956 sizeof(wl1271_band_5ghz));
4957
4958 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4959 &wl->bands[IEEE80211_BAND_2GHZ];
4960 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4961 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004962
Kalle Valo12bd8942010-03-18 12:26:33 +02004963 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004964 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004965
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004966 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4967
Felipe Balbia390e852011-10-06 10:07:44 +03004968 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004969
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004970 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004971 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004972
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004973 wl->hw->max_rx_aggregation_subframes = 8;
4974
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004975 return 0;
4976}
4977
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004978#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004979
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004980static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004981{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004982 struct ieee80211_hw *hw;
4983 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004984 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004985 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004986
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004987 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004988
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004989 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4990 if (!hw) {
4991 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004992 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004993 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004994 }
4995
4996 wl = hw->priv;
4997 memset(wl, 0, sizeof(*wl));
4998
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004999 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005000 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005001
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005002 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005003
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005004 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005005 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005006 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5007
Ido Yariva6208652011-03-01 15:14:41 +02005008 skb_queue_head_init(&wl->deferred_rx_queue);
5009 skb_queue_head_init(&wl->deferred_tx_queue);
5010
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005011 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005012 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005013 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5014 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5015 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005016
Eliad Peller92ef8962011-06-07 12:50:46 +03005017 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5018 if (!wl->freezable_wq) {
5019 ret = -ENOMEM;
5020 goto err_hw;
5021 }
5022
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005023 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005024 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005025 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005026 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005027 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005028 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005029 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005030 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005031 wl->ap_ps_map = 0;
5032 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005033 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005034 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005035 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005036 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005037 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005038 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005039 wl->fwlog_size = 0;
5040 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005041
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005042 /* The system link is always allocated */
5043 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5044
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005045 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005046 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005047 wl->tx_frames[i] = NULL;
5048
5049 spin_lock_init(&wl->wl_lock);
5050
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005051 wl->state = WL1271_STATE_OFF;
5052 mutex_init(&wl->mutex);
5053
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005054 /* Apply default driver configuration. */
5055 wl1271_conf_init(wl);
5056
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005057 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5058 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5059 if (!wl->aggr_buf) {
5060 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005061 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005062 }
5063
Ido Yariv990f5de2011-03-31 10:06:59 +02005064 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5065 if (!wl->dummy_packet) {
5066 ret = -ENOMEM;
5067 goto err_aggr;
5068 }
5069
Ido Yariv95dac04f2011-06-06 14:57:06 +03005070 /* Allocate one page for the FW log */
5071 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5072 if (!wl->fwlog) {
5073 ret = -ENOMEM;
5074 goto err_dummy_packet;
5075 }
5076
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005077 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005078
Ido Yariv990f5de2011-03-31 10:06:59 +02005079err_dummy_packet:
5080 dev_kfree_skb(wl->dummy_packet);
5081
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005082err_aggr:
5083 free_pages((unsigned long)wl->aggr_buf, order);
5084
Eliad Peller92ef8962011-06-07 12:50:46 +03005085err_wq:
5086 destroy_workqueue(wl->freezable_wq);
5087
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005088err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005089 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005090 ieee80211_free_hw(hw);
5091
5092err_hw_alloc:
5093
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005094 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005095}
5096
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005097static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005098{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005099 /* Unblock any fwlog readers */
5100 mutex_lock(&wl->mutex);
5101 wl->fwlog_size = -1;
5102 wake_up_interruptible_all(&wl->fwlog_waitq);
5103 mutex_unlock(&wl->mutex);
5104
Felipe Balbif79f8902011-10-06 13:05:25 +03005105 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005106
Felipe Balbif79f8902011-10-06 13:05:25 +03005107 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005108
Felipe Balbif79f8902011-10-06 13:05:25 +03005109 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005110 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005111 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005112 free_pages((unsigned long)wl->aggr_buf,
5113 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005114
5115 wl1271_debugfs_exit(wl);
5116
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005117 vfree(wl->fw);
5118 wl->fw = NULL;
5119 kfree(wl->nvs);
5120 wl->nvs = NULL;
5121
5122 kfree(wl->fw_status);
5123 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005124 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005125
5126 ieee80211_free_hw(wl->hw);
5127
5128 return 0;
5129}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005130
Felipe Balbia390e852011-10-06 10:07:44 +03005131static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5132{
5133 struct wl1271 *wl = cookie;
5134 unsigned long flags;
5135
5136 wl1271_debug(DEBUG_IRQ, "IRQ");
5137
5138 /* complete the ELP completion */
5139 spin_lock_irqsave(&wl->wl_lock, flags);
5140 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5141 if (wl->elp_compl) {
5142 complete(wl->elp_compl);
5143 wl->elp_compl = NULL;
5144 }
5145
5146 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5147 /* don't enqueue a work right now. mark it as pending */
5148 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5149 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5150 disable_irq_nosync(wl->irq);
5151 pm_wakeup_event(wl->dev, 0);
5152 spin_unlock_irqrestore(&wl->wl_lock, flags);
5153 return IRQ_HANDLED;
5154 }
5155 spin_unlock_irqrestore(&wl->wl_lock, flags);
5156
5157 return IRQ_WAKE_THREAD;
5158}
5159
Felipe Balbice2a2172011-10-05 14:12:55 +03005160static int __devinit wl12xx_probe(struct platform_device *pdev)
5161{
Felipe Balbia390e852011-10-06 10:07:44 +03005162 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5163 struct ieee80211_hw *hw;
5164 struct wl1271 *wl;
5165 unsigned long irqflags;
5166 int ret = -ENODEV;
5167
5168 hw = wl1271_alloc_hw();
5169 if (IS_ERR(hw)) {
5170 wl1271_error("can't allocate hw");
5171 ret = PTR_ERR(hw);
5172 goto out;
5173 }
5174
5175 wl = hw->priv;
5176 wl->irq = platform_get_irq(pdev, 0);
5177 wl->ref_clock = pdata->board_ref_clock;
5178 wl->tcxo_clock = pdata->board_tcxo_clock;
5179 wl->platform_quirks = pdata->platform_quirks;
5180 wl->set_power = pdata->set_power;
5181 wl->dev = &pdev->dev;
5182 wl->if_ops = pdata->ops;
5183
5184 platform_set_drvdata(pdev, wl);
5185
5186 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5187 irqflags = IRQF_TRIGGER_RISING;
5188 else
5189 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5190
5191 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5192 irqflags,
5193 pdev->name, wl);
5194 if (ret < 0) {
5195 wl1271_error("request_irq() failed: %d", ret);
5196 goto out_free_hw;
5197 }
5198
5199 ret = enable_irq_wake(wl->irq);
5200 if (!ret) {
5201 wl->irq_wake_enabled = true;
5202 device_init_wakeup(wl->dev, 1);
5203 if (pdata->pwr_in_suspend)
5204 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5205
5206 }
5207 disable_irq(wl->irq);
5208
5209 ret = wl1271_init_ieee80211(wl);
5210 if (ret)
5211 goto out_irq;
5212
5213 ret = wl1271_register_hw(wl);
5214 if (ret)
5215 goto out_irq;
5216
Felipe Balbif79f8902011-10-06 13:05:25 +03005217 /* Create sysfs file to control bt coex state */
5218 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5219 if (ret < 0) {
5220 wl1271_error("failed to create sysfs file bt_coex_state");
5221 goto out_irq;
5222 }
5223
5224 /* Create sysfs file to get HW PG version */
5225 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5226 if (ret < 0) {
5227 wl1271_error("failed to create sysfs file hw_pg_ver");
5228 goto out_bt_coex_state;
5229 }
5230
5231 /* Create sysfs file for the FW log */
5232 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5233 if (ret < 0) {
5234 wl1271_error("failed to create sysfs file fwlog");
5235 goto out_hw_pg_ver;
5236 }
5237
Felipe Balbice2a2172011-10-05 14:12:55 +03005238 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005239
Felipe Balbif79f8902011-10-06 13:05:25 +03005240out_hw_pg_ver:
5241 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5242
5243out_bt_coex_state:
5244 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5245
Felipe Balbia390e852011-10-06 10:07:44 +03005246out_irq:
5247 free_irq(wl->irq, wl);
5248
5249out_free_hw:
5250 wl1271_free_hw(wl);
5251
5252out:
5253 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005254}
5255
5256static int __devexit wl12xx_remove(struct platform_device *pdev)
5257{
Felipe Balbia390e852011-10-06 10:07:44 +03005258 struct wl1271 *wl = platform_get_drvdata(pdev);
5259
5260 if (wl->irq_wake_enabled) {
5261 device_init_wakeup(wl->dev, 0);
5262 disable_irq_wake(wl->irq);
5263 }
5264 wl1271_unregister_hw(wl);
5265 free_irq(wl->irq, wl);
5266 wl1271_free_hw(wl);
5267
Felipe Balbice2a2172011-10-05 14:12:55 +03005268 return 0;
5269}
5270
5271static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005272 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005273 { } /* Terminating Entry */
5274};
5275MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5276
5277static struct platform_driver wl12xx_driver = {
5278 .probe = wl12xx_probe,
5279 .remove = __devexit_p(wl12xx_remove),
5280 .id_table = wl12xx_id_table,
5281 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005282 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005283 .owner = THIS_MODULE,
5284 }
5285};
5286
5287static int __init wl12xx_init(void)
5288{
5289 return platform_driver_register(&wl12xx_driver);
5290}
5291module_init(wl12xx_init);
5292
5293static void __exit wl12xx_exit(void)
5294{
5295 platform_driver_unregister(&wl12xx_driver);
5296}
5297module_exit(wl12xx_exit);
5298
Guy Eilam491bbd62011-01-12 10:33:29 +01005299u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005300EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005301module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005302MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5303
Ido Yariv95dac04f2011-06-06 14:57:06 +03005304module_param_named(fwlog, fwlog_param, charp, 0);
5305MODULE_PARM_DESC(keymap,
5306 "FW logger options: continuous, ondemand, dbgpins or disable");
5307
Eliad Peller2a5bff02011-08-25 18:10:59 +03005308module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5309MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5310
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005311MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005312MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005313MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");