blob: b9a3fe4972749c71cbb98a18e4a4e83f5e9ff1c5 [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-Cohen958b20e2011-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 Oikarinen01ac17e2009-12-11 15:41:02 +02001293 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001294 ret = wl1271_power_on(wl);
1295 if (ret < 0)
1296 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001297 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001298 wl1271_io_reset(wl);
1299 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001300
1301 /* We don't need a real memory partition here, because we only want
1302 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001303 memset(&partition, 0, sizeof(partition));
1304 partition.reg.start = REGISTERS_BASE;
1305 partition.reg.size = REGISTERS_DOWN_SIZE;
1306 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001307
1308 /* ELP module wake up */
1309 wl1271_fw_wakeup(wl);
1310
1311 /* whal_FwCtrl_BootSm() */
1312
1313 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001314 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315
1316 /* 1. check if chip id is valid */
1317
1318 switch (wl->chip.id) {
1319 case CHIP_ID_1271_PG10:
1320 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1321 wl->chip.id);
1322
1323 ret = wl1271_setup(wl);
1324 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001325 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001326 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001328
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329 case CHIP_ID_1271_PG20:
1330 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1331 wl->chip.id);
1332
1333 ret = wl1271_setup(wl);
1334 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001335 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001336 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001337 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001338
Shahar Levi0830cee2011-03-06 16:32:20 +02001339 case CHIP_ID_1283_PG20:
1340 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1341 wl->chip.id);
1342
1343 ret = wl1271_setup(wl);
1344 if (ret < 0)
1345 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001346
Luciano Coelhoce39def2011-11-03 08:44:41 +02001347 if (!wl1271_set_block_size(wl))
1348 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001349 break;
1350 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001351 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001352 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001353 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001354 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001355 }
1356
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001357 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001358 ret = wl1271_fetch_firmware(wl);
1359 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001360 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001361 }
1362
1363 /* No NVS from netlink, try to get it from the filesystem */
1364 if (wl->nvs == NULL) {
1365 ret = wl1271_fetch_nvs(wl);
1366 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001367 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368 }
1369
1370out:
1371 return ret;
1372}
1373
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001374int wl1271_plt_start(struct wl1271 *wl)
1375{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001376 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001377 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001378 int ret;
1379
1380 mutex_lock(&wl->mutex);
1381
1382 wl1271_notice("power up");
1383
1384 if (wl->state != WL1271_STATE_OFF) {
1385 wl1271_error("cannot go into PLT state because not "
1386 "in off state: %d", wl->state);
1387 ret = -EBUSY;
1388 goto out;
1389 }
1390
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001391 while (retries) {
1392 retries--;
1393 ret = wl1271_chip_wakeup(wl);
1394 if (ret < 0)
1395 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001396
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001397 ret = wl1271_boot(wl);
1398 if (ret < 0)
1399 goto power_off;
1400
1401 ret = wl1271_plt_init(wl);
1402 if (ret < 0)
1403 goto irq_disable;
1404
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001405 wl->state = WL1271_STATE_PLT;
1406 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001407 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001408
Gery Kahn6f07b722011-07-18 14:21:49 +03001409 /* update hw/fw version info in wiphy struct */
1410 wiphy->hw_version = wl->chip.id;
1411 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1412 sizeof(wiphy->fw_version));
1413
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001414 goto out;
1415
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001416irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001417 mutex_unlock(&wl->mutex);
1418 /* Unlocking the mutex in the middle of handling is
1419 inherently unsafe. In this case we deem it safe to do,
1420 because we need to let any possibly pending IRQ out of
1421 the system (and while we are WL1271_STATE_OFF the IRQ
1422 work function will not do anything.) Also, any other
1423 possible concurrent operations will fail due to the
1424 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001425 wl1271_disable_interrupts(wl);
1426 wl1271_flush_deferred_work(wl);
1427 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001428 mutex_lock(&wl->mutex);
1429power_off:
1430 wl1271_power_off(wl);
1431 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001432
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001433 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1434 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001435out:
1436 mutex_unlock(&wl->mutex);
1437
1438 return ret;
1439}
1440
Luciano Coelho4623ec72011-03-21 19:26:41 +02001441static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001442{
1443 int ret = 0;
1444
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001445 wl1271_notice("power down");
1446
1447 if (wl->state != WL1271_STATE_PLT) {
1448 wl1271_error("cannot power down because not in PLT "
1449 "state: %d", wl->state);
1450 ret = -EBUSY;
1451 goto out;
1452 }
1453
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454 wl1271_power_off(wl);
1455
1456 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001457 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001458
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001459 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001460 wl1271_disable_interrupts(wl);
1461 wl1271_flush_deferred_work(wl);
1462 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001463 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001464 mutex_lock(&wl->mutex);
1465out:
1466 return ret;
1467}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001468
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001469int wl1271_plt_stop(struct wl1271 *wl)
1470{
1471 int ret;
1472
1473 mutex_lock(&wl->mutex);
1474 ret = __wl1271_plt_stop(wl);
1475 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001476 return ret;
1477}
1478
Johannes Berg7bb45682011-02-24 14:42:06 +01001479static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001480{
1481 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001482 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1483 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001484 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001485 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001486 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001487 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001488
Eliad Peller0f168012011-10-11 13:52:25 +02001489 if (vif)
1490 wlvif = wl12xx_vif_to_data(vif);
1491
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001492 mapping = skb_get_queue_mapping(skb);
1493 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001494
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001495 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001496
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001497 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001498
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001499 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001500 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001501 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001502 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
1503 dev_kfree_skb(skb);
1504 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001505 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001506
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001507 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1508 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1509
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001510 wl->tx_queue_count[q]++;
1511
1512 /*
1513 * The workqueue is slow to process the tx_queue and we need stop
1514 * the queue here, otherwise the queue will get too long.
1515 */
1516 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1517 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1518 ieee80211_stop_queue(wl->hw, mapping);
1519 set_bit(q, &wl->stopped_queues_map);
1520 }
1521
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001522 /*
1523 * The chip specific setup must run before the first TX packet -
1524 * before that, the tx_work will not be initialized!
1525 */
1526
Ido Yarivb07d4032011-03-01 15:14:43 +02001527 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1528 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001529 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001530
Arik Nemtsov04216da2011-08-14 13:17:38 +03001531out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001532 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001533}
1534
Shahar Leviae47c452011-03-06 16:32:14 +02001535int wl1271_tx_dummy_packet(struct wl1271 *wl)
1536{
Ido Yariv990f5de2011-03-31 10:06:59 +02001537 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001538 int q;
1539
1540 /* no need to queue a new dummy packet if one is already pending */
1541 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1542 return 0;
1543
1544 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001545
Ido Yariv990f5de2011-03-31 10:06:59 +02001546 spin_lock_irqsave(&wl->wl_lock, flags);
1547 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001548 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001549 spin_unlock_irqrestore(&wl->wl_lock, flags);
1550
1551 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1552 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001553 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001554
1555 /*
1556 * If the FW TX is busy, TX work will be scheduled by the threaded
1557 * interrupt handler function
1558 */
1559 return 0;
1560}
1561
1562/*
1563 * The size of the dummy packet should be at least 1400 bytes. However, in
1564 * order to minimize the number of bus transactions, aligning it to 512 bytes
1565 * boundaries could be beneficial, performance wise
1566 */
1567#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1568
Luciano Coelhocf27d862011-04-01 21:08:23 +03001569static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001570{
1571 struct sk_buff *skb;
1572 struct ieee80211_hdr_3addr *hdr;
1573 unsigned int dummy_packet_size;
1574
1575 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1576 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1577
1578 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001579 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001580 wl1271_warning("Failed to allocate a dummy packet skb");
1581 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001582 }
1583
1584 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1585
1586 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1587 memset(hdr, 0, sizeof(*hdr));
1588 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001589 IEEE80211_STYPE_NULLFUNC |
1590 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001591
Ido Yariv990f5de2011-03-31 10:06:59 +02001592 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001593
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001594 /* Dummy packets require the TID to be management */
1595 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001596
1597 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001598 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001599 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001600
Ido Yariv990f5de2011-03-31 10:06:59 +02001601 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001602}
1603
Ido Yariv990f5de2011-03-31 10:06:59 +02001604
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001605static struct notifier_block wl1271_dev_notifier = {
1606 .notifier_call = wl1271_dev_notify,
1607};
1608
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001609#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001610static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1611 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001612{
Eliad Pellere85d1622011-06-27 13:06:43 +03001613 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001614
Eliad Peller94390642011-05-13 11:57:13 +03001615 mutex_lock(&wl->mutex);
1616
Eliad Pellerba8447f2011-10-10 10:13:00 +02001617 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001618 goto out_unlock;
1619
Eliad Peller94390642011-05-13 11:57:13 +03001620 ret = wl1271_ps_elp_wakeup(wl);
1621 if (ret < 0)
1622 goto out_unlock;
1623
1624 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001625 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001626 DECLARE_COMPLETION_ONSTACK(compl);
1627
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001628 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001629 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001630 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001631 if (ret < 0)
1632 goto out_sleep;
1633
1634 /* we must unlock here so we will be able to get events */
1635 wl1271_ps_elp_sleep(wl);
1636 mutex_unlock(&wl->mutex);
1637
1638 ret = wait_for_completion_timeout(
1639 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1640 if (ret <= 0) {
1641 wl1271_warning("couldn't enter ps mode!");
1642 ret = -EBUSY;
1643 goto out;
1644 }
1645
1646 /* take mutex again, and wakeup */
1647 mutex_lock(&wl->mutex);
1648
1649 ret = wl1271_ps_elp_wakeup(wl);
1650 if (ret < 0)
1651 goto out_unlock;
1652 }
1653out_sleep:
1654 wl1271_ps_elp_sleep(wl);
1655out_unlock:
1656 mutex_unlock(&wl->mutex);
1657out:
1658 return ret;
1659
1660}
1661
Eliad Peller0603d892011-10-05 11:55:51 +02001662static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1663 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001664{
Eliad Pellere85d1622011-06-27 13:06:43 +03001665 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001666
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001667 mutex_lock(&wl->mutex);
1668
Eliad Peller53d40d02011-10-10 10:13:02 +02001669 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001670 goto out_unlock;
1671
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001672 ret = wl1271_ps_elp_wakeup(wl);
1673 if (ret < 0)
1674 goto out_unlock;
1675
Eliad Peller0603d892011-10-05 11:55:51 +02001676 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001677
1678 wl1271_ps_elp_sleep(wl);
1679out_unlock:
1680 mutex_unlock(&wl->mutex);
1681 return ret;
1682
1683}
1684
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001685static int wl1271_configure_suspend(struct wl1271 *wl,
1686 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001687{
Eliad Peller536129c2011-10-05 11:55:45 +02001688 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001689 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001690 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001691 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001692 return 0;
1693}
1694
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001695static void wl1271_configure_resume(struct wl1271 *wl,
1696 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001697{
1698 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001699 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1700 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001701
1702 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001703 return;
1704
1705 mutex_lock(&wl->mutex);
1706 ret = wl1271_ps_elp_wakeup(wl);
1707 if (ret < 0)
1708 goto out;
1709
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001710 if (is_sta) {
1711 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001712 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001713 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001714 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001715 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001716 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001717 }
Eliad Peller94390642011-05-13 11:57:13 +03001718
1719 wl1271_ps_elp_sleep(wl);
1720out:
1721 mutex_unlock(&wl->mutex);
1722}
1723
Eliad Peller402e48612011-05-13 11:57:09 +03001724static int wl1271_op_suspend(struct ieee80211_hw *hw,
1725 struct cfg80211_wowlan *wow)
1726{
1727 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001728 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001729 int ret;
1730
Eliad Peller402e48612011-05-13 11:57:09 +03001731 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001732 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001733
Eliad Peller4a859df2011-06-06 12:21:52 +03001734 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001735 wl12xx_for_each_wlvif(wl, wlvif) {
1736 ret = wl1271_configure_suspend(wl, wlvif);
1737 if (ret < 0) {
1738 wl1271_warning("couldn't prepare device to suspend");
1739 return ret;
1740 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001741 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001742 /* flush any remaining work */
1743 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001744
1745 /*
1746 * disable and re-enable interrupts in order to flush
1747 * the threaded_irq
1748 */
1749 wl1271_disable_interrupts(wl);
1750
1751 /*
1752 * set suspended flag to avoid triggering a new threaded_irq
1753 * work. no need for spinlock as interrupts are disabled.
1754 */
1755 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1756
1757 wl1271_enable_interrupts(wl);
1758 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001759 wl12xx_for_each_wlvif(wl, wlvif) {
1760 flush_delayed_work(&wlvif->pspoll_work);
1761 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001762 flush_delayed_work(&wl->elp_work);
1763
Eliad Peller402e48612011-05-13 11:57:09 +03001764 return 0;
1765}
1766
1767static int wl1271_op_resume(struct ieee80211_hw *hw)
1768{
1769 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001770 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001771 unsigned long flags;
1772 bool run_irq_work = false;
1773
Eliad Peller402e48612011-05-13 11:57:09 +03001774 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1775 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001776 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001777
1778 /*
1779 * re-enable irq_work enqueuing, and call irq_work directly if
1780 * there is a pending work.
1781 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001782 spin_lock_irqsave(&wl->wl_lock, flags);
1783 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1784 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1785 run_irq_work = true;
1786 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001787
Eliad Peller4a859df2011-06-06 12:21:52 +03001788 if (run_irq_work) {
1789 wl1271_debug(DEBUG_MAC80211,
1790 "run postponed irq_work directly");
1791 wl1271_irq(0, wl);
1792 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001793 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001794 wl12xx_for_each_wlvif(wl, wlvif) {
1795 wl1271_configure_resume(wl, wlvif);
1796 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001797 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001798
Eliad Peller402e48612011-05-13 11:57:09 +03001799 return 0;
1800}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001801#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001802
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001803static int wl1271_op_start(struct ieee80211_hw *hw)
1804{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001805 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1806
1807 /*
1808 * We have to delay the booting of the hardware because
1809 * we need to know the local MAC address before downloading and
1810 * initializing the firmware. The MAC address cannot be changed
1811 * after boot, and without the proper MAC address, the firmware
1812 * will not function properly.
1813 *
1814 * The MAC address is first known when the corresponding interface
1815 * is added. That is where we will initialize the hardware.
1816 */
1817
1818 return 0;
1819}
1820
1821static void wl1271_op_stop(struct ieee80211_hw *hw)
1822{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001823 struct wl1271 *wl = hw->priv;
1824 int i;
1825
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001826 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001827
Eliad Peller10c8cd02011-10-10 10:13:06 +02001828 mutex_lock(&wl->mutex);
1829 if (wl->state == WL1271_STATE_OFF) {
1830 mutex_unlock(&wl->mutex);
1831 return;
1832 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001833 /*
1834 * this must be before the cancel_work calls below, so that the work
1835 * functions don't perform further work.
1836 */
1837 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001838 mutex_unlock(&wl->mutex);
1839
1840 mutex_lock(&wl_list_mutex);
1841 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001842 mutex_unlock(&wl_list_mutex);
1843
1844 wl1271_disable_interrupts(wl);
1845 wl1271_flush_deferred_work(wl);
1846 cancel_delayed_work_sync(&wl->scan_complete_work);
1847 cancel_work_sync(&wl->netstack_work);
1848 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001849 cancel_delayed_work_sync(&wl->elp_work);
1850
1851 /* let's notify MAC80211 about the remaining pending TX frames */
1852 wl12xx_tx_reset(wl, true);
1853 mutex_lock(&wl->mutex);
1854
1855 wl1271_power_off(wl);
1856
1857 wl->band = IEEE80211_BAND_2GHZ;
1858
1859 wl->rx_counter = 0;
1860 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1861 wl->tx_blocks_available = 0;
1862 wl->tx_allocated_blocks = 0;
1863 wl->tx_results_count = 0;
1864 wl->tx_packets_count = 0;
1865 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001866 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1867 wl->ap_fw_ps_map = 0;
1868 wl->ap_ps_map = 0;
1869 wl->sched_scanning = false;
1870 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1871 memset(wl->links_map, 0, sizeof(wl->links_map));
1872 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1873 wl->active_sta_count = 0;
1874
1875 /* The system link is always allocated */
1876 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1877
1878 /*
1879 * this is performed after the cancel_work calls and the associated
1880 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1881 * get executed before all these vars have been reset.
1882 */
1883 wl->flags = 0;
1884
1885 wl->tx_blocks_freed = 0;
1886
1887 for (i = 0; i < NUM_TX_QUEUES; i++) {
1888 wl->tx_pkts_freed[i] = 0;
1889 wl->tx_allocated_pkts[i] = 0;
1890 }
1891
1892 wl1271_debugfs_reset(wl);
1893
1894 kfree(wl->fw_status);
1895 wl->fw_status = NULL;
1896 kfree(wl->tx_res_if);
1897 wl->tx_res_if = NULL;
1898 kfree(wl->target_mem_map);
1899 wl->target_mem_map = NULL;
1900
1901 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001902}
1903
Eliad Pellere5a359f2011-10-10 10:13:15 +02001904static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1905{
1906 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1907 WL12XX_MAX_RATE_POLICIES);
1908 if (policy >= WL12XX_MAX_RATE_POLICIES)
1909 return -EBUSY;
1910
1911 __set_bit(policy, wl->rate_policies_map);
1912 *idx = policy;
1913 return 0;
1914}
1915
1916static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1917{
1918 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1919 return;
1920
1921 __clear_bit(*idx, wl->rate_policies_map);
1922 *idx = WL12XX_MAX_RATE_POLICIES;
1923}
1924
Eliad Peller536129c2011-10-05 11:55:45 +02001925static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001926{
Eliad Peller536129c2011-10-05 11:55:45 +02001927 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001928 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001929 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001930 return WL1271_ROLE_P2P_GO;
1931 else
1932 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001933
1934 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001935 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001936 return WL1271_ROLE_P2P_CL;
1937 else
1938 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001939
Eliad Peller227e81e2011-08-14 13:17:26 +03001940 case BSS_TYPE_IBSS:
1941 return WL1271_ROLE_IBSS;
1942
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001943 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001944 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001945 }
1946 return WL12XX_INVALID_ROLE_TYPE;
1947}
1948
Eliad Peller83587502011-10-10 10:12:53 +02001949static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001950{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001951 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001952 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001953
Eliad Peller48e93e42011-10-10 10:12:58 +02001954 /* clear everything but the persistent data */
1955 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001956
1957 switch (ieee80211_vif_type_p2p(vif)) {
1958 case NL80211_IFTYPE_P2P_CLIENT:
1959 wlvif->p2p = 1;
1960 /* fall-through */
1961 case NL80211_IFTYPE_STATION:
1962 wlvif->bss_type = BSS_TYPE_STA_BSS;
1963 break;
1964 case NL80211_IFTYPE_ADHOC:
1965 wlvif->bss_type = BSS_TYPE_IBSS;
1966 break;
1967 case NL80211_IFTYPE_P2P_GO:
1968 wlvif->p2p = 1;
1969 /* fall-through */
1970 case NL80211_IFTYPE_AP:
1971 wlvif->bss_type = BSS_TYPE_AP_BSS;
1972 break;
1973 default:
1974 wlvif->bss_type = MAX_BSS_TYPE;
1975 return -EOPNOTSUPP;
1976 }
1977
Eliad Peller0603d892011-10-05 11:55:51 +02001978 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001979 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001980 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001981
Eliad Pellere936bbe2011-10-05 11:55:56 +02001982 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1983 wlvif->bss_type == BSS_TYPE_IBSS) {
1984 /* init sta/ibss data */
1985 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001986 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1987 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1988 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001989 } else {
1990 /* init ap data */
1991 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1992 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001993 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1994 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1995 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1996 wl12xx_allocate_rate_policy(wl,
1997 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001998 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001999
Eliad Peller83587502011-10-10 10:12:53 +02002000 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
2001 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002002 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002003 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002004 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02002005 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
2006
Eliad Peller1b92f152011-10-10 10:13:09 +02002007 /*
2008 * mac80211 configures some values globally, while we treat them
2009 * per-interface. thus, on init, we have to copy them from wl
2010 */
2011 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02002012 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02002013 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02002014
Eliad Peller9eb599e2011-10-10 10:12:59 +02002015 INIT_WORK(&wlvif->rx_streaming_enable_work,
2016 wl1271_rx_streaming_enable_work);
2017 INIT_WORK(&wlvif->rx_streaming_disable_work,
2018 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02002019 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02002020 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02002021
Eliad Peller9eb599e2011-10-10 10:12:59 +02002022 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
2023 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002024 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002025}
2026
Eliad Peller1d095472011-10-10 10:12:49 +02002027static bool wl12xx_init_fw(struct wl1271 *wl)
2028{
2029 int retries = WL1271_BOOT_RETRIES;
2030 bool booted = false;
2031 struct wiphy *wiphy = wl->hw->wiphy;
2032 int ret;
2033
2034 while (retries) {
2035 retries--;
2036 ret = wl1271_chip_wakeup(wl);
2037 if (ret < 0)
2038 goto power_off;
2039
2040 ret = wl1271_boot(wl);
2041 if (ret < 0)
2042 goto power_off;
2043
2044 ret = wl1271_hw_init(wl);
2045 if (ret < 0)
2046 goto irq_disable;
2047
2048 booted = true;
2049 break;
2050
2051irq_disable:
2052 mutex_unlock(&wl->mutex);
2053 /* Unlocking the mutex in the middle of handling is
2054 inherently unsafe. In this case we deem it safe to do,
2055 because we need to let any possibly pending IRQ out of
2056 the system (and while we are WL1271_STATE_OFF the IRQ
2057 work function will not do anything.) Also, any other
2058 possible concurrent operations will fail due to the
2059 current state, hence the wl1271 struct should be safe. */
2060 wl1271_disable_interrupts(wl);
2061 wl1271_flush_deferred_work(wl);
2062 cancel_work_sync(&wl->netstack_work);
2063 mutex_lock(&wl->mutex);
2064power_off:
2065 wl1271_power_off(wl);
2066 }
2067
2068 if (!booted) {
2069 wl1271_error("firmware boot failed despite %d retries",
2070 WL1271_BOOT_RETRIES);
2071 goto out;
2072 }
2073
2074 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2075
2076 /* update hw/fw version info in wiphy struct */
2077 wiphy->hw_version = wl->chip.id;
2078 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2079 sizeof(wiphy->fw_version));
2080
2081 /*
2082 * Now we know if 11a is supported (info from the NVS), so disable
2083 * 11a channels if not supported
2084 */
2085 if (!wl->enable_11a)
2086 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2087
2088 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2089 wl->enable_11a ? "" : "not ");
2090
2091 wl->state = WL1271_STATE_ON;
2092out:
2093 return booted;
2094}
2095
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002096static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2097 struct ieee80211_vif *vif)
2098{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002099 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002100 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002101 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002102 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002103 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002104
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002105 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002106 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002107
2108 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002109 ret = wl1271_ps_elp_wakeup(wl);
2110 if (ret < 0)
2111 goto out_unlock;
2112
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002113 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002114 wl1271_debug(DEBUG_MAC80211,
2115 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002116 ret = -EBUSY;
2117 goto out;
2118 }
2119
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002120 /*
2121 * in some very corner case HW recovery scenarios its possible to
2122 * get here before __wl1271_op_remove_interface is complete, so
2123 * opt out if that is the case.
2124 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002125 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2126 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002127 ret = -EBUSY;
2128 goto out;
2129 }
2130
Eliad Peller83587502011-10-10 10:12:53 +02002131 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002132 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002133 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002134
Eliad Peller252efa42011-10-05 11:56:00 +02002135 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002136 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002137 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2138 ret = -EINVAL;
2139 goto out;
2140 }
Eliad Peller1d095472011-10-10 10:12:49 +02002141
Eliad Peller784f6942011-10-05 11:55:39 +02002142 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002143 * TODO: after the nvs issue will be solved, move this block
2144 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002145 */
Eliad Peller1d095472011-10-10 10:12:49 +02002146 if (wl->state == WL1271_STATE_OFF) {
2147 /*
2148 * we still need this in order to configure the fw
2149 * while uploading the nvs
2150 */
2151 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002152
Eliad Peller1d095472011-10-10 10:12:49 +02002153 booted = wl12xx_init_fw(wl);
2154 if (!booted) {
2155 ret = -EINVAL;
2156 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002157 }
Eliad Peller1d095472011-10-10 10:12:49 +02002158 }
Eliad Peller04e80792011-08-14 13:17:09 +03002159
Eliad Peller1d095472011-10-10 10:12:49 +02002160 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2161 wlvif->bss_type == BSS_TYPE_IBSS) {
2162 /*
2163 * The device role is a special role used for
2164 * rx and tx frames prior to association (as
2165 * the STA role can get packets only from
2166 * its associated bssid)
2167 */
Eliad Peller784f6942011-10-05 11:55:39 +02002168 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002169 WL1271_ROLE_DEVICE,
2170 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002171 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002172 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002173 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002174
Eliad Peller1d095472011-10-10 10:12:49 +02002175 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2176 role_type, &wlvif->role_id);
2177 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002178 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002179
2180 ret = wl1271_init_vif_specific(wl, vif);
2181 if (ret < 0)
2182 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002183
2184 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002185 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002186 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002187
2188 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2189 wl->ap_count++;
2190 else
2191 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002192out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002193 wl1271_ps_elp_sleep(wl);
2194out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002195 mutex_unlock(&wl->mutex);
2196
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002197 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002198 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002199 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002200 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002201
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002202 return ret;
2203}
2204
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002205static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002206 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002207 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002208{
Eliad Peller536129c2011-10-05 11:55:45 +02002209 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002210 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002211
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002212 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002213
Eliad Peller10c8cd02011-10-10 10:13:06 +02002214 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2215 return;
2216
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002217 wl->vif = NULL;
2218
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002219 /* because of hardware recovery, we may get here twice */
2220 if (wl->state != WL1271_STATE_ON)
2221 return;
2222
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002223 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002224
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002225 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002226 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002227 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002228
Eliad Pellerbaf62772011-10-10 10:12:52 +02002229 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2230 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002231 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002232 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002233 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002234 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002235 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002236 }
2237
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002238 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2239 /* disable active roles */
2240 ret = wl1271_ps_elp_wakeup(wl);
2241 if (ret < 0)
2242 goto deinit;
2243
Eliad Peller536129c2011-10-05 11:55:45 +02002244 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002245 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002246 if (ret < 0)
2247 goto deinit;
2248 }
2249
Eliad Peller0603d892011-10-05 11:55:51 +02002250 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002251 if (ret < 0)
2252 goto deinit;
2253
2254 wl1271_ps_elp_sleep(wl);
2255 }
2256deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002257 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002258 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002259
2260 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2261 wlvif->bss_type == BSS_TYPE_IBSS) {
2262 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2263 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2264 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2265 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2266 } else {
2267 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2268 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2269 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2270 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2271 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2272 wl12xx_free_rate_policy(wl,
2273 &wlvif->ap.ucast_rate_idx[i]);
2274 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002275
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002276 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002277 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002278 if (wl->last_wlvif == wlvif)
2279 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002280 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002281 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002282 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002283 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002284
Eliad Pellera4e41302011-10-11 11:49:15 +02002285 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2286 wl->ap_count--;
2287 else
2288 wl->sta_count--;
2289
Eliad Pellerbaf62772011-10-10 10:12:52 +02002290 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002291 del_timer_sync(&wlvif->rx_streaming_timer);
2292 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2293 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002294 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002295
Eliad Pellerbaf62772011-10-10 10:12:52 +02002296 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002297}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002298
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002299static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2300 struct ieee80211_vif *vif)
2301{
2302 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002303 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002304 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002305
2306 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002307
2308 if (wl->state == WL1271_STATE_OFF ||
2309 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2310 goto out;
2311
Juuso Oikarinen67353292010-11-18 15:19:02 +02002312 /*
2313 * wl->vif can be null here if someone shuts down the interface
2314 * just when hardware recovery has been started.
2315 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002316 wl12xx_for_each_wlvif(wl, iter) {
2317 if (iter != wlvif)
2318 continue;
2319
Eliad Peller536129c2011-10-05 11:55:45 +02002320 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002321 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002322 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002323 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002324out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002325 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002326 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002327}
2328
Eliad Peller87fbcb02011-10-05 11:55:41 +02002329static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2330 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002331{
2332 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002333 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002334
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002335 /*
2336 * One of the side effects of the JOIN command is that is clears
2337 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2338 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002339 * Currently the only valid scenario for JOIN during association
2340 * is on roaming, in which case we will also be given new keys.
2341 * Keep the below message for now, unless it starts bothering
2342 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002343 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002344 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002345 wl1271_info("JOIN while associated.");
2346
2347 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002348 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002349
Eliad Peller227e81e2011-08-14 13:17:26 +03002350 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002351 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002352 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002353 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002354 if (ret < 0)
2355 goto out;
2356
Eliad Pellerba8447f2011-10-10 10:13:00 +02002357 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002358 goto out;
2359
2360 /*
2361 * The join command disable the keep-alive mode, shut down its process,
2362 * and also clear the template config, so we need to reset it all after
2363 * the join. The acx_aid starts the keep-alive process, and the order
2364 * of the commands below is relevant.
2365 */
Eliad Peller0603d892011-10-05 11:55:51 +02002366 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002367 if (ret < 0)
2368 goto out;
2369
Eliad Peller0603d892011-10-05 11:55:51 +02002370 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002371 if (ret < 0)
2372 goto out;
2373
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002374 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002375 if (ret < 0)
2376 goto out;
2377
Eliad Peller0603d892011-10-05 11:55:51 +02002378 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2379 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002380 ACX_KEEP_ALIVE_TPL_VALID);
2381 if (ret < 0)
2382 goto out;
2383
2384out:
2385 return ret;
2386}
2387
Eliad Peller0603d892011-10-05 11:55:51 +02002388static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002389{
2390 int ret;
2391
Eliad Peller52630c52011-10-10 10:13:08 +02002392 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002393 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2394
Shahar Levi6d158ff2011-09-08 13:01:33 +03002395 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002396 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002397 }
2398
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002399 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002400 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002401 if (ret < 0)
2402 goto out;
2403
Oz Krakowskib992c682011-06-26 10:36:02 +03002404 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002405 wlvif->tx_security_last_seq_lsb = 0;
2406 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002407
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002408out:
2409 return ret;
2410}
2411
Eliad Peller87fbcb02011-10-05 11:55:41 +02002412static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002413{
Eliad Peller1b92f152011-10-10 10:13:09 +02002414 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002415 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002416}
2417
Eliad Peller251c1772011-08-14 13:17:17 +03002418static bool wl12xx_is_roc(struct wl1271 *wl)
2419{
2420 u8 role_id;
2421
2422 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2423 if (role_id >= WL12XX_MAX_ROLES)
2424 return false;
2425
2426 return true;
2427}
2428
Eliad Peller87fbcb02011-10-05 11:55:41 +02002429static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2430 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002431{
2432 int ret;
2433
2434 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002435 /* no need to croc if we weren't busy (e.g. during boot) */
2436 if (wl12xx_is_roc(wl)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002437 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002438 if (ret < 0)
2439 goto out;
2440 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002441 wlvif->rate_set =
2442 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2443 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002444 if (ret < 0)
2445 goto out;
2446 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002447 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002448 ACX_KEEP_ALIVE_TPL_INVALID);
2449 if (ret < 0)
2450 goto out;
2451 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2452 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002453 /* The current firmware only supports sched_scan in idle */
2454 if (wl->sched_scanning) {
2455 wl1271_scan_sched_scan_stop(wl);
2456 ieee80211_sched_scan_stopped(wl->hw);
2457 }
2458
Eliad Peller679a6732011-10-11 11:55:44 +02002459 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002460 if (ret < 0)
2461 goto out;
2462 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2463 }
2464
2465out:
2466 return ret;
2467}
2468
Eliad Peller9f259c42011-10-10 10:13:12 +02002469static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2470 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002471{
Eliad Peller9f259c42011-10-10 10:13:12 +02002472 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2473 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002474
2475 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2476
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002477 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002478 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002479 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002480 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002481 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002482 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002483 wlvif->band = conf->channel->band;
2484 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002485
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002486 if (!is_ap) {
2487 /*
2488 * FIXME: the mac80211 should really provide a fixed
2489 * rate to use here. for now, just use the smallest
2490 * possible rate for the band as a fixed rate for
2491 * association frames and other control messages.
2492 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002493 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002494 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002495
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002496 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002497 wl1271_tx_min_rate_get(wl,
2498 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002499 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002500 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002501 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002502 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002503
Eliad Pellerba8447f2011-10-10 10:13:00 +02002504 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2505 &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002506 if (wl12xx_is_roc(wl)) {
2507 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002508 ret = wl12xx_croc(wl,
2509 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002510 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002511 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002512 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002513 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002514 if (ret < 0)
2515 wl1271_warning("cmd join on channel "
2516 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002517 } else {
2518 /*
2519 * change the ROC channel. do it only if we are
2520 * not idle. otherwise, CROC will be called
2521 * anyway.
2522 */
2523 if (wl12xx_is_roc(wl) &&
2524 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002525 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002526 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002527 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002528
Eliad Peller679a6732011-10-11 11:55:44 +02002529 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002530 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002531 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002532 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002533 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002534 }
2535 }
2536
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002537 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002538 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002539 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002540 if (ret < 0)
2541 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002542 }
2543
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002544 /*
2545 * if mac80211 changes the PSM mode, make sure the mode is not
2546 * incorrectly changed after the pspoll failure active window.
2547 */
2548 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002549 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002550
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002551 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002552 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2553 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002554
2555 /*
2556 * We enter PSM only if we're already associated.
2557 * If we're not, we'll enter it when joining an SSID,
2558 * through the bss_info_changed() hook.
2559 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002560 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002561 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002562 ret = wl1271_ps_set_mode(wl, wlvif,
2563 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002564 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002565 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002566 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002567 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002568 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002569
Eliad Pellerc29bb002011-10-10 10:13:03 +02002570 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002571
Eliad Pellerc29bb002011-10-10 10:13:03 +02002572 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002573 ret = wl1271_ps_set_mode(wl, wlvif,
2574 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002575 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002576 }
2577
Eliad Peller6bd65022011-10-10 10:13:11 +02002578 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002579 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002580 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002581 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002582
Eliad Peller6bd65022011-10-10 10:13:11 +02002583 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002584 }
2585
Eliad Peller9f259c42011-10-10 10:13:12 +02002586 return 0;
2587}
2588
2589static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2590{
2591 struct wl1271 *wl = hw->priv;
2592 struct wl12xx_vif *wlvif;
2593 struct ieee80211_conf *conf = &hw->conf;
2594 int channel, ret = 0;
2595
2596 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2597
2598 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2599 " changed 0x%x",
2600 channel,
2601 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2602 conf->power_level,
2603 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2604 changed);
2605
2606 /*
2607 * mac80211 will go to idle nearly immediately after transmitting some
2608 * frames, such as the deauth. To make sure those frames reach the air,
2609 * wait here until the TX queue is fully flushed.
2610 */
2611 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2612 (conf->flags & IEEE80211_CONF_IDLE))
2613 wl1271_tx_flush(wl);
2614
2615 mutex_lock(&wl->mutex);
2616
2617 /* we support configuring the channel and band even while off */
2618 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2619 wl->band = conf->channel->band;
2620 wl->channel = channel;
2621 }
2622
2623 if (changed & IEEE80211_CONF_CHANGE_POWER)
2624 wl->power_level = conf->power_level;
2625
2626 if (unlikely(wl->state == WL1271_STATE_OFF))
2627 goto out;
2628
2629 ret = wl1271_ps_elp_wakeup(wl);
2630 if (ret < 0)
2631 goto out;
2632
2633 /* configure each interface */
2634 wl12xx_for_each_wlvif(wl, wlvif) {
2635 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2636 if (ret < 0)
2637 goto out_sleep;
2638 }
2639
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002640out_sleep:
2641 wl1271_ps_elp_sleep(wl);
2642
2643out:
2644 mutex_unlock(&wl->mutex);
2645
2646 return ret;
2647}
2648
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002649struct wl1271_filter_params {
2650 bool enabled;
2651 int mc_list_length;
2652 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2653};
2654
Jiri Pirko22bedad2010-04-01 21:22:57 +00002655static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2656 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002657{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002658 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002659 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002660 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002661
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002662 if (unlikely(wl->state == WL1271_STATE_OFF))
2663 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002664
Juuso Oikarinen74441132009-10-13 12:47:53 +03002665 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002666 if (!fp) {
2667 wl1271_error("Out of memory setting filters.");
2668 return 0;
2669 }
2670
2671 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002672 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002673 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2674 fp->enabled = false;
2675 } else {
2676 fp->enabled = true;
2677 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002678 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002679 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002680 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002681 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002682 }
2683
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002684 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002685}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002686
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002687#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2688 FIF_ALLMULTI | \
2689 FIF_FCSFAIL | \
2690 FIF_BCN_PRBRESP_PROMISC | \
2691 FIF_CONTROL | \
2692 FIF_OTHER_BSS)
2693
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002694static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2695 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002696 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002697{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002698 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002699 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002700 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002701
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002702 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002703
Arik Nemtsov7d057862010-10-16 19:25:35 +02002704 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2705 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002706
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002707 mutex_lock(&wl->mutex);
2708
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002709 *total &= WL1271_SUPPORTED_FILTERS;
2710 changed &= WL1271_SUPPORTED_FILTERS;
2711
2712 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002713 goto out;
2714
Ido Yariva6208652011-03-01 15:14:41 +02002715 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002716 if (ret < 0)
2717 goto out;
2718
Eliad Peller6e8cd332011-10-10 10:13:13 +02002719 wl12xx_for_each_wlvif(wl, wlvif) {
2720 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2721 if (*total & FIF_ALLMULTI)
2722 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2723 false,
2724 NULL, 0);
2725 else if (fp)
2726 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2727 fp->enabled,
2728 fp->mc_list,
2729 fp->mc_list_length);
2730 if (ret < 0)
2731 goto out_sleep;
2732 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002733 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002734
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002735 /*
2736 * the fw doesn't provide an api to configure the filters. instead,
2737 * the filters configuration is based on the active roles / ROC
2738 * state.
2739 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002740
2741out_sleep:
2742 wl1271_ps_elp_sleep(wl);
2743
2744out:
2745 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002746 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002747}
2748
Eliad Peller170d0e62011-10-05 11:56:06 +02002749static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2750 u8 id, u8 key_type, u8 key_size,
2751 const u8 *key, u8 hlid, u32 tx_seq_32,
2752 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002753{
2754 struct wl1271_ap_key *ap_key;
2755 int i;
2756
2757 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2758
2759 if (key_size > MAX_KEY_SIZE)
2760 return -EINVAL;
2761
2762 /*
2763 * Find next free entry in ap_keys. Also check we are not replacing
2764 * an existing key.
2765 */
2766 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002767 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002768 break;
2769
Eliad Peller170d0e62011-10-05 11:56:06 +02002770 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002771 wl1271_warning("trying to record key replacement");
2772 return -EINVAL;
2773 }
2774 }
2775
2776 if (i == MAX_NUM_KEYS)
2777 return -EBUSY;
2778
2779 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2780 if (!ap_key)
2781 return -ENOMEM;
2782
2783 ap_key->id = id;
2784 ap_key->key_type = key_type;
2785 ap_key->key_size = key_size;
2786 memcpy(ap_key->key, key, key_size);
2787 ap_key->hlid = hlid;
2788 ap_key->tx_seq_32 = tx_seq_32;
2789 ap_key->tx_seq_16 = tx_seq_16;
2790
Eliad Peller170d0e62011-10-05 11:56:06 +02002791 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002792 return 0;
2793}
2794
Eliad Peller170d0e62011-10-05 11:56:06 +02002795static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002796{
2797 int i;
2798
2799 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002800 kfree(wlvif->ap.recorded_keys[i]);
2801 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002802 }
2803}
2804
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002805static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002806{
2807 int i, ret = 0;
2808 struct wl1271_ap_key *key;
2809 bool wep_key_added = false;
2810
2811 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002812 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002813 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002814 break;
2815
Eliad Peller170d0e62011-10-05 11:56:06 +02002816 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002817 hlid = key->hlid;
2818 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002819 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002820
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002821 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002822 key->id, key->key_type,
2823 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002824 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002825 key->tx_seq_16);
2826 if (ret < 0)
2827 goto out;
2828
2829 if (key->key_type == KEY_WEP)
2830 wep_key_added = true;
2831 }
2832
2833 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002834 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002835 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002836 if (ret < 0)
2837 goto out;
2838 }
2839
2840out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002841 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002842 return ret;
2843}
2844
Eliad Peller536129c2011-10-05 11:55:45 +02002845static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2846 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002847 u8 key_size, const u8 *key, u32 tx_seq_32,
2848 u16 tx_seq_16, struct ieee80211_sta *sta)
2849{
2850 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002851 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002852
2853 if (is_ap) {
2854 struct wl1271_station *wl_sta;
2855 u8 hlid;
2856
2857 if (sta) {
2858 wl_sta = (struct wl1271_station *)sta->drv_priv;
2859 hlid = wl_sta->hlid;
2860 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002861 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002862 }
2863
Eliad Peller53d40d02011-10-10 10:13:02 +02002864 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002865 /*
2866 * We do not support removing keys after AP shutdown.
2867 * Pretend we do to make mac80211 happy.
2868 */
2869 if (action != KEY_ADD_OR_REPLACE)
2870 return 0;
2871
Eliad Peller170d0e62011-10-05 11:56:06 +02002872 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002873 key_type, key_size,
2874 key, hlid, tx_seq_32,
2875 tx_seq_16);
2876 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002877 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002878 id, key_type, key_size,
2879 key, hlid, tx_seq_32,
2880 tx_seq_16);
2881 }
2882
2883 if (ret < 0)
2884 return ret;
2885 } else {
2886 const u8 *addr;
2887 static const u8 bcast_addr[ETH_ALEN] = {
2888 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2889 };
2890
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002891 /*
2892 * A STA set to GEM cipher requires 2 tx spare blocks.
2893 * Return to default value when GEM cipher key is removed
2894 */
2895 if (key_type == KEY_GEM) {
2896 if (action == KEY_ADD_OR_REPLACE)
2897 wl->tx_spare_blocks = 2;
2898 else if (action == KEY_REMOVE)
2899 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2900 }
2901
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002902 addr = sta ? sta->addr : bcast_addr;
2903
2904 if (is_zero_ether_addr(addr)) {
2905 /* We dont support TX only encryption */
2906 return -EOPNOTSUPP;
2907 }
2908
2909 /* The wl1271 does not allow to remove unicast keys - they
2910 will be cleared automatically on next CMD_JOIN. Ignore the
2911 request silently, as we dont want the mac80211 to emit
2912 an error message. */
2913 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2914 return 0;
2915
Eliad Peller010d3d32011-08-14 13:17:31 +03002916 /* don't remove key if hlid was already deleted */
2917 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002918 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002919 return 0;
2920
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002921 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002922 id, key_type, key_size,
2923 key, addr, tx_seq_32,
2924 tx_seq_16);
2925 if (ret < 0)
2926 return ret;
2927
2928 /* the default WEP key needs to be configured at least once */
2929 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002930 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002931 wlvif->default_key,
2932 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002933 if (ret < 0)
2934 return ret;
2935 }
2936 }
2937
2938 return 0;
2939}
2940
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002941static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2942 struct ieee80211_vif *vif,
2943 struct ieee80211_sta *sta,
2944 struct ieee80211_key_conf *key_conf)
2945{
2946 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002947 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002948 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002949 u32 tx_seq_32 = 0;
2950 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002951 u8 key_type;
2952
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002953 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2954
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002955 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002956 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002957 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002958 key_conf->keylen, key_conf->flags);
2959 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2960
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002961 mutex_lock(&wl->mutex);
2962
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002963 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2964 ret = -EAGAIN;
2965 goto out_unlock;
2966 }
2967
Ido Yariva6208652011-03-01 15:14:41 +02002968 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002969 if (ret < 0)
2970 goto out_unlock;
2971
Johannes Berg97359d12010-08-10 09:46:38 +02002972 switch (key_conf->cipher) {
2973 case WLAN_CIPHER_SUITE_WEP40:
2974 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002975 key_type = KEY_WEP;
2976
2977 key_conf->hw_key_idx = key_conf->keyidx;
2978 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002979 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002980 key_type = KEY_TKIP;
2981
2982 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002983 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2984 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002985 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002986 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002987 key_type = KEY_AES;
2988
2989 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Eliad Peller48e93e42011-10-10 10:12:58 +02002990 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2991 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002992 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002993 case WL1271_CIPHER_SUITE_GEM:
2994 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002995 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2996 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002997 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002998 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002999 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003000
3001 ret = -EOPNOTSUPP;
3002 goto out_sleep;
3003 }
3004
3005 switch (cmd) {
3006 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003007 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003008 key_conf->keyidx, key_type,
3009 key_conf->keylen, key_conf->key,
3010 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003011 if (ret < 0) {
3012 wl1271_error("Could not add or replace key");
3013 goto out_sleep;
3014 }
3015 break;
3016
3017 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003018 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003019 key_conf->keyidx, key_type,
3020 key_conf->keylen, key_conf->key,
3021 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003022 if (ret < 0) {
3023 wl1271_error("Could not remove key");
3024 goto out_sleep;
3025 }
3026 break;
3027
3028 default:
3029 wl1271_error("Unsupported key cmd 0x%x", cmd);
3030 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003031 break;
3032 }
3033
3034out_sleep:
3035 wl1271_ps_elp_sleep(wl);
3036
3037out_unlock:
3038 mutex_unlock(&wl->mutex);
3039
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003040 return ret;
3041}
3042
3043static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003044 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003045 struct cfg80211_scan_request *req)
3046{
3047 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003048 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3049
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003050 int ret;
3051 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003052 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003053
3054 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3055
3056 if (req->n_ssids) {
3057 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003058 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003059 }
3060
3061 mutex_lock(&wl->mutex);
3062
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003063 if (wl->state == WL1271_STATE_OFF) {
3064 /*
3065 * We cannot return -EBUSY here because cfg80211 will expect
3066 * a call to ieee80211_scan_completed if we do - in this case
3067 * there won't be any call.
3068 */
3069 ret = -EAGAIN;
3070 goto out;
3071 }
3072
Ido Yariva6208652011-03-01 15:14:41 +02003073 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003074 if (ret < 0)
3075 goto out;
3076
Eliad Peller251c1772011-08-14 13:17:17 +03003077 /* cancel ROC before scanning */
3078 if (wl12xx_is_roc(wl)) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02003079 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03003080 /* don't allow scanning right now */
3081 ret = -EBUSY;
3082 goto out_sleep;
3083 }
Eliad Peller679a6732011-10-11 11:55:44 +02003084 wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003085 }
3086
Eliad Peller784f6942011-10-05 11:55:39 +02003087 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003088out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003089 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003090out:
3091 mutex_unlock(&wl->mutex);
3092
3093 return ret;
3094}
3095
Eliad Peller73ecce32011-06-27 13:06:45 +03003096static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3097 struct ieee80211_vif *vif)
3098{
3099 struct wl1271 *wl = hw->priv;
3100 int ret;
3101
3102 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3103
3104 mutex_lock(&wl->mutex);
3105
3106 if (wl->state == WL1271_STATE_OFF)
3107 goto out;
3108
3109 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3110 goto out;
3111
3112 ret = wl1271_ps_elp_wakeup(wl);
3113 if (ret < 0)
3114 goto out;
3115
3116 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3117 ret = wl1271_scan_stop(wl);
3118 if (ret < 0)
3119 goto out_sleep;
3120 }
3121 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3122 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003123 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003124 wl->scan.req = NULL;
3125 ieee80211_scan_completed(wl->hw, true);
3126
3127out_sleep:
3128 wl1271_ps_elp_sleep(wl);
3129out:
3130 mutex_unlock(&wl->mutex);
3131
3132 cancel_delayed_work_sync(&wl->scan_complete_work);
3133}
3134
Luciano Coelho33c2c062011-05-10 14:46:02 +03003135static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3136 struct ieee80211_vif *vif,
3137 struct cfg80211_sched_scan_request *req,
3138 struct ieee80211_sched_scan_ies *ies)
3139{
3140 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003141 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003142 int ret;
3143
3144 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3145
3146 mutex_lock(&wl->mutex);
3147
3148 ret = wl1271_ps_elp_wakeup(wl);
3149 if (ret < 0)
3150 goto out;
3151
Eliad Peller536129c2011-10-05 11:55:45 +02003152 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003153 if (ret < 0)
3154 goto out_sleep;
3155
Eliad Peller536129c2011-10-05 11:55:45 +02003156 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003157 if (ret < 0)
3158 goto out_sleep;
3159
3160 wl->sched_scanning = true;
3161
3162out_sleep:
3163 wl1271_ps_elp_sleep(wl);
3164out:
3165 mutex_unlock(&wl->mutex);
3166 return ret;
3167}
3168
3169static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3170 struct ieee80211_vif *vif)
3171{
3172 struct wl1271 *wl = hw->priv;
3173 int ret;
3174
3175 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3176
3177 mutex_lock(&wl->mutex);
3178
3179 ret = wl1271_ps_elp_wakeup(wl);
3180 if (ret < 0)
3181 goto out;
3182
3183 wl1271_scan_sched_scan_stop(wl);
3184
3185 wl1271_ps_elp_sleep(wl);
3186out:
3187 mutex_unlock(&wl->mutex);
3188}
3189
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003190static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3191{
3192 struct wl1271 *wl = hw->priv;
3193 int ret = 0;
3194
3195 mutex_lock(&wl->mutex);
3196
3197 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3198 ret = -EAGAIN;
3199 goto out;
3200 }
3201
Ido Yariva6208652011-03-01 15:14:41 +02003202 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003203 if (ret < 0)
3204 goto out;
3205
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003206 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003207 if (ret < 0)
3208 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3209
3210 wl1271_ps_elp_sleep(wl);
3211
3212out:
3213 mutex_unlock(&wl->mutex);
3214
3215 return ret;
3216}
3217
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003218static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3219{
3220 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003221 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003222 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003223
3224 mutex_lock(&wl->mutex);
3225
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003226 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3227 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003228 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003229 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003230
Ido Yariva6208652011-03-01 15:14:41 +02003231 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003232 if (ret < 0)
3233 goto out;
3234
Eliad Peller6e8cd332011-10-10 10:13:13 +02003235 wl12xx_for_each_wlvif(wl, wlvif) {
3236 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3237 if (ret < 0)
3238 wl1271_warning("set rts threshold failed: %d", ret);
3239 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003240 wl1271_ps_elp_sleep(wl);
3241
3242out:
3243 mutex_unlock(&wl->mutex);
3244
3245 return ret;
3246}
3247
Eliad Peller1fe9f162011-10-05 11:55:48 +02003248static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003249 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003250{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003251 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003252 u8 ssid_len;
3253 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3254 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003255
Eliad Peller889cb362011-05-01 09:56:45 +03003256 if (!ptr) {
3257 wl1271_error("No SSID in IEs!");
3258 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003259 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003260
Eliad Peller889cb362011-05-01 09:56:45 +03003261 ssid_len = ptr[1];
3262 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3263 wl1271_error("SSID is too long!");
3264 return -EINVAL;
3265 }
3266
Eliad Peller1fe9f162011-10-05 11:55:48 +02003267 wlvif->ssid_len = ssid_len;
3268 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003269 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003270}
3271
Eliad Pellerd48055d2011-09-15 12:07:04 +03003272static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3273{
3274 int len;
3275 const u8 *next, *end = skb->data + skb->len;
3276 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3277 skb->len - ieoffset);
3278 if (!ie)
3279 return;
3280 len = ie[1] + 2;
3281 next = ie + len;
3282 memmove(ie, next, end - next);
3283 skb_trim(skb, skb->len - len);
3284}
3285
Eliad Peller26b4bf22011-09-15 12:07:05 +03003286static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3287 unsigned int oui, u8 oui_type,
3288 int ieoffset)
3289{
3290 int len;
3291 const u8 *next, *end = skb->data + skb->len;
3292 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3293 skb->data + ieoffset,
3294 skb->len - ieoffset);
3295 if (!ie)
3296 return;
3297 len = ie[1] + 2;
3298 next = ie + len;
3299 memmove(ie, next, end - next);
3300 skb_trim(skb, skb->len - len);
3301}
3302
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003303static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
Eliad Peller1fe9f162011-10-05 11:55:48 +02003304 struct ieee80211_vif *vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003305 u8 *probe_rsp_data,
3306 size_t probe_rsp_len,
3307 u32 rates)
3308{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003309 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3310 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003311 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3312 int ssid_ie_offset, ie_offset, templ_len;
3313 const u8 *ptr;
3314
3315 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003316 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003317 return wl1271_cmd_template_set(wl,
3318 CMD_TEMPL_AP_PROBE_RESPONSE,
3319 probe_rsp_data,
3320 probe_rsp_len, 0,
3321 rates);
3322
3323 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3324 wl1271_error("probe_rsp template too big");
3325 return -EINVAL;
3326 }
3327
3328 /* start searching from IE offset */
3329 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3330
3331 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3332 probe_rsp_len - ie_offset);
3333 if (!ptr) {
3334 wl1271_error("No SSID in beacon!");
3335 return -EINVAL;
3336 }
3337
3338 ssid_ie_offset = ptr - probe_rsp_data;
3339 ptr += (ptr[1] + 2);
3340
3341 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3342
3343 /* insert SSID from bss_conf */
3344 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3345 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3346 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3347 bss_conf->ssid, bss_conf->ssid_len);
3348 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3349
3350 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3351 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3352 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3353
3354 return wl1271_cmd_template_set(wl,
3355 CMD_TEMPL_AP_PROBE_RESPONSE,
3356 probe_rsp_templ,
3357 templ_len, 0,
3358 rates);
3359}
3360
Arik Nemtsove78a2872010-10-16 19:07:21 +02003361static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003362 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003363 struct ieee80211_bss_conf *bss_conf,
3364 u32 changed)
3365{
Eliad Peller0603d892011-10-05 11:55:51 +02003366 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003367 int ret = 0;
3368
3369 if (changed & BSS_CHANGED_ERP_SLOT) {
3370 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003371 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003372 else
Eliad Peller0603d892011-10-05 11:55:51 +02003373 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003374 if (ret < 0) {
3375 wl1271_warning("Set slot time failed %d", ret);
3376 goto out;
3377 }
3378 }
3379
3380 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3381 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003382 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003383 else
Eliad Peller0603d892011-10-05 11:55:51 +02003384 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003385 }
3386
3387 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3388 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003389 ret = wl1271_acx_cts_protect(wl, wlvif,
3390 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003391 else
Eliad Peller0603d892011-10-05 11:55:51 +02003392 ret = wl1271_acx_cts_protect(wl, wlvif,
3393 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003394 if (ret < 0) {
3395 wl1271_warning("Set ctsprotect failed %d", ret);
3396 goto out;
3397 }
3398 }
3399
3400out:
3401 return ret;
3402}
3403
3404static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3405 struct ieee80211_vif *vif,
3406 struct ieee80211_bss_conf *bss_conf,
3407 u32 changed)
3408{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003409 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003410 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003411 int ret = 0;
3412
3413 if ((changed & BSS_CHANGED_BEACON_INT)) {
3414 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3415 bss_conf->beacon_int);
3416
Eliad Peller6a899792011-10-05 11:55:58 +02003417 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003418 }
3419
3420 if ((changed & BSS_CHANGED_BEACON)) {
3421 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003422 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003423 int ieoffset = offsetof(struct ieee80211_mgmt,
3424 u.beacon.variable);
3425 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3426 u16 tmpl_id;
3427
3428 if (!beacon)
3429 goto out;
3430
3431 wl1271_debug(DEBUG_MASTER, "beacon updated");
3432
Eliad Peller1fe9f162011-10-05 11:55:48 +02003433 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003434 if (ret < 0) {
3435 dev_kfree_skb(beacon);
3436 goto out;
3437 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003438 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003439 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3440 CMD_TEMPL_BEACON;
3441 ret = wl1271_cmd_template_set(wl, tmpl_id,
3442 beacon->data,
3443 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003444 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003445 if (ret < 0) {
3446 dev_kfree_skb(beacon);
3447 goto out;
3448 }
3449
Eliad Pellerd48055d2011-09-15 12:07:04 +03003450 /* remove TIM ie from probe response */
3451 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3452
Eliad Peller26b4bf22011-09-15 12:07:05 +03003453 /*
3454 * remove p2p ie from probe response.
3455 * the fw reponds to probe requests that don't include
3456 * the p2p ie. probe requests with p2p ie will be passed,
3457 * and will be responded by the supplicant (the spec
3458 * forbids including the p2p ie when responding to probe
3459 * requests that didn't include it).
3460 */
3461 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3462 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3463
Arik Nemtsove78a2872010-10-16 19:07:21 +02003464 hdr = (struct ieee80211_hdr *) beacon->data;
3465 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3466 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003467 if (is_ap)
Eliad Peller1fe9f162011-10-05 11:55:48 +02003468 ret = wl1271_ap_set_probe_resp_tmpl(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003469 beacon->data,
3470 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003471 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003472 else
3473 ret = wl1271_cmd_template_set(wl,
3474 CMD_TEMPL_PROBE_RESPONSE,
3475 beacon->data,
3476 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003477 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003478 dev_kfree_skb(beacon);
3479 if (ret < 0)
3480 goto out;
3481 }
3482
3483out:
3484 return ret;
3485}
3486
3487/* AP mode changes */
3488static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003489 struct ieee80211_vif *vif,
3490 struct ieee80211_bss_conf *bss_conf,
3491 u32 changed)
3492{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003493 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003494 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003495
Arik Nemtsove78a2872010-10-16 19:07:21 +02003496 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3497 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003498
Eliad Peller87fbcb02011-10-05 11:55:41 +02003499 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003500 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003501 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003502 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003503
Eliad Peller87fbcb02011-10-05 11:55:41 +02003504 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003505 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003506 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003507 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003508 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003509
Eliad Peller784f6942011-10-05 11:55:39 +02003510 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003511 if (ret < 0)
3512 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003513 }
3514
Arik Nemtsove78a2872010-10-16 19:07:21 +02003515 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3516 if (ret < 0)
3517 goto out;
3518
3519 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3520 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003521 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003522 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003523 if (ret < 0)
3524 goto out;
3525
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003526 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003527 if (ret < 0)
3528 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003529
Eliad Peller53d40d02011-10-10 10:13:02 +02003530 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003531 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003532 }
3533 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003534 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003535 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003536 if (ret < 0)
3537 goto out;
3538
Eliad Peller53d40d02011-10-10 10:13:02 +02003539 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003540 wl1271_debug(DEBUG_AP, "stopped AP");
3541 }
3542 }
3543 }
3544
Eliad Peller0603d892011-10-05 11:55:51 +02003545 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003546 if (ret < 0)
3547 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003548
3549 /* Handle HT information change */
3550 if ((changed & BSS_CHANGED_HT) &&
3551 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003552 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003553 bss_conf->ht_operation_mode);
3554 if (ret < 0) {
3555 wl1271_warning("Set ht information failed %d", ret);
3556 goto out;
3557 }
3558 }
3559
Arik Nemtsove78a2872010-10-16 19:07:21 +02003560out:
3561 return;
3562}
3563
3564/* STA/IBSS mode changes */
3565static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3566 struct ieee80211_vif *vif,
3567 struct ieee80211_bss_conf *bss_conf,
3568 u32 changed)
3569{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003570 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003571 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003572 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003573 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003574 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003575 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003576 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003577 bool sta_exists = false;
3578 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003579
3580 if (is_ibss) {
3581 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3582 changed);
3583 if (ret < 0)
3584 goto out;
3585 }
3586
Eliad Peller227e81e2011-08-14 13:17:26 +03003587 if (changed & BSS_CHANGED_IBSS) {
3588 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003589 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003590 ibss_joined = true;
3591 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003592 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3593 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003594 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003595 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003596 }
3597 }
3598 }
3599
3600 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003601 do_join = true;
3602
3603 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003604 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003605 do_join = true;
3606
Eliad Peller227e81e2011-08-14 13:17:26 +03003607 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003608 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3609 bss_conf->enable_beacon ? "enabled" : "disabled");
3610
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003611 do_join = true;
3612 }
3613
Arik Nemtsove78a2872010-10-16 19:07:21 +02003614 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003615 bool enable = false;
3616 if (bss_conf->cqm_rssi_thold)
3617 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003618 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003619 bss_conf->cqm_rssi_thold,
3620 bss_conf->cqm_rssi_hyst);
3621 if (ret < 0)
3622 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003623 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003624 }
3625
Eliad Pellercdf09492011-10-05 11:55:44 +02003626 if (changed & BSS_CHANGED_BSSID)
3627 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003628 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003629 if (ret < 0)
3630 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003631
Eliad Peller784f6942011-10-05 11:55:39 +02003632 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003633 if (ret < 0)
3634 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003635
Eliad Pellerfa287b82010-12-26 09:27:50 +01003636 /* Need to update the BSSID (for filtering etc) */
3637 do_join = true;
3638 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003639
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003640 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3641 rcu_read_lock();
3642 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3643 if (!sta)
3644 goto sta_not_found;
3645
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003646 /* save the supp_rates of the ap */
3647 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3648 if (sta->ht_cap.ht_supported)
3649 sta_rate_set |=
3650 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003651 sta_ht_cap = sta->ht_cap;
3652 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003653
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003654sta_not_found:
3655 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003656 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003657
Arik Nemtsove78a2872010-10-16 19:07:21 +02003658 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003659 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003660 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003661 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003662 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003663 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003664
Eliad Peller74ec8392011-10-05 11:56:02 +02003665 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003666
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003667 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003668 * use basic rates from AP, and determine lowest rate
3669 * to use with control frames.
3670 */
3671 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003672 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003673 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003674 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003675 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003676 wl1271_tx_min_rate_get(wl,
3677 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003678 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003679 wlvif->rate_set =
3680 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003681 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003682 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003683 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003684 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003685 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003686
3687 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003688 * with wl1271, we don't need to update the
3689 * beacon_int and dtim_period, because the firmware
3690 * updates it by itself when the first beacon is
3691 * received after a join.
3692 */
Eliad Peller6840e372011-10-05 11:55:50 +02003693 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003694 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003695 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003696
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003697 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003698 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003699 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003700 dev_kfree_skb(wlvif->probereq);
3701 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003702 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003703 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003704 ieoffset = offsetof(struct ieee80211_mgmt,
3705 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003706 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003707
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003708 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003709 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003710 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003711 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003712 } else {
3713 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003714 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003715 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3716 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003717 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003718 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3719 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003720 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003721
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003722 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003723 dev_kfree_skb(wlvif->probereq);
3724 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003725
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003726 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003727 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003728
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003729 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003730 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003731 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003732 wl1271_tx_min_rate_get(wl,
3733 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003734 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003735 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003736 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003737
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003738 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003739 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003740
3741 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003742 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003743 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003744 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003745
3746 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003747 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003748 u32 conf_flags = wl->hw->conf.flags;
3749 /*
3750 * we might have to disable roc, if there was
3751 * no IF_OPER_UP notification.
3752 */
3753 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003754 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003755 if (ret < 0)
3756 goto out;
3757 }
3758 /*
3759 * (we also need to disable roc in case of
3760 * roaming on the same channel. until we will
3761 * have a better flow...)
3762 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003763 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3764 ret = wl12xx_croc(wl,
3765 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003766 if (ret < 0)
3767 goto out;
3768 }
3769
Eliad Peller0603d892011-10-05 11:55:51 +02003770 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003771 if (!(conf_flags & IEEE80211_CONF_IDLE))
3772 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003773 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003774 }
3775 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003776
Eliad Pellerd192d262011-05-24 14:33:08 +03003777 if (changed & BSS_CHANGED_IBSS) {
3778 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3779 bss_conf->ibss_joined);
3780
3781 if (bss_conf->ibss_joined) {
3782 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003783 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003784 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003785 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003786 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003787 wl1271_tx_min_rate_get(wl,
3788 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003789
Shahar Levi06b660e2011-09-05 13:54:36 +03003790 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003791 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3792 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003793 if (ret < 0)
3794 goto out;
3795 }
3796 }
3797
Eliad Peller0603d892011-10-05 11:55:51 +02003798 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003799 if (ret < 0)
3800 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003801
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003802 if (changed & BSS_CHANGED_ARP_FILTER) {
3803 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003804 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003805
Eliad Pellerc5312772010-12-09 11:31:27 +02003806 if (bss_conf->arp_addr_cnt == 1 &&
3807 bss_conf->arp_filter_enabled) {
3808 /*
3809 * The template should have been configured only upon
3810 * association. however, it seems that the correct ip
3811 * isn't being set (when sending), so we have to
3812 * reconfigure the template upon every ip change.
3813 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003814 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003815 if (ret < 0) {
3816 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003817 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003818 }
3819
Eliad Peller0603d892011-10-05 11:55:51 +02003820 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003821 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003822 addr);
3823 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003824 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003825
3826 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003827 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003828 }
3829
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003830 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003831 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003832 if (ret < 0) {
3833 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003834 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003835 }
Eliad Peller251c1772011-08-14 13:17:17 +03003836
3837 /* ROC until connected (after EAPOL exchange) */
3838 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003839 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003840 if (ret < 0)
3841 goto out;
3842
Eliad Pellerba8447f2011-10-10 10:13:00 +02003843 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003844 ieee80211_get_operstate(vif));
3845 }
3846 /*
3847 * stop device role if started (we might already be in
3848 * STA role). TODO: make it better.
3849 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003850 if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) {
Eliad Peller679a6732011-10-11 11:55:44 +02003851 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003852 if (ret < 0)
3853 goto out;
3854 }
Eliad Peller05dba352011-08-23 16:37:01 +03003855
3856 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003857 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3858 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003859 enum wl1271_cmd_ps_mode mode;
3860
3861 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003862 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003863 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003864 true);
3865 if (ret < 0)
3866 goto out;
3867 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003868 }
3869
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003870 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003871 if (sta_exists) {
3872 if ((changed & BSS_CHANGED_HT) &&
3873 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003874 ret = wl1271_acx_set_ht_capabilities(wl,
3875 &sta_ht_cap,
3876 true,
Eliad Peller154da672011-10-05 11:55:53 +02003877 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003878 if (ret < 0) {
3879 wl1271_warning("Set ht cap true failed %d",
3880 ret);
3881 goto out;
3882 }
3883 }
3884 /* handle new association without HT and disassociation */
3885 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003886 ret = wl1271_acx_set_ht_capabilities(wl,
3887 &sta_ht_cap,
3888 false,
Eliad Peller154da672011-10-05 11:55:53 +02003889 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003890 if (ret < 0) {
3891 wl1271_warning("Set ht cap false failed %d",
3892 ret);
3893 goto out;
3894 }
3895 }
3896 }
3897
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003898 /* Handle HT information change. Done after join. */
3899 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003900 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003901 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003902 bss_conf->ht_operation_mode);
3903 if (ret < 0) {
3904 wl1271_warning("Set ht information failed %d", ret);
3905 goto out;
3906 }
3907 }
3908
Arik Nemtsove78a2872010-10-16 19:07:21 +02003909out:
3910 return;
3911}
3912
3913static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3914 struct ieee80211_vif *vif,
3915 struct ieee80211_bss_conf *bss_conf,
3916 u32 changed)
3917{
3918 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003919 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3920 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003921 int ret;
3922
3923 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3924 (int)changed);
3925
3926 mutex_lock(&wl->mutex);
3927
3928 if (unlikely(wl->state == WL1271_STATE_OFF))
3929 goto out;
3930
Eliad Peller10c8cd02011-10-10 10:13:06 +02003931 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3932 goto out;
3933
Ido Yariva6208652011-03-01 15:14:41 +02003934 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003935 if (ret < 0)
3936 goto out;
3937
3938 if (is_ap)
3939 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3940 else
3941 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3942
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003943 wl1271_ps_elp_sleep(wl);
3944
3945out:
3946 mutex_unlock(&wl->mutex);
3947}
3948
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003949static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3950 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003951 const struct ieee80211_tx_queue_params *params)
3952{
3953 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003954 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003955 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003956 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003957
3958 mutex_lock(&wl->mutex);
3959
3960 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3961
Kalle Valo4695dc92010-03-18 12:26:38 +02003962 if (params->uapsd)
3963 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3964 else
3965 ps_scheme = CONF_PS_SCHEME_LEGACY;
3966
Arik Nemtsov488fc542010-10-16 20:33:45 +02003967 if (wl->state == WL1271_STATE_OFF) {
3968 /*
3969 * If the state is off, the parameters will be recorded and
3970 * configured on init. This happens in AP-mode.
3971 */
3972 struct conf_tx_ac_category *conf_ac =
3973 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3974 struct conf_tx_tid *conf_tid =
3975 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3976
3977 conf_ac->ac = wl1271_tx_get_queue(queue);
3978 conf_ac->cw_min = (u8)params->cw_min;
3979 conf_ac->cw_max = params->cw_max;
3980 conf_ac->aifsn = params->aifs;
3981 conf_ac->tx_op_limit = params->txop << 5;
3982
3983 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3984 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3985 conf_tid->tsid = wl1271_tx_get_queue(queue);
3986 conf_tid->ps_scheme = ps_scheme;
3987 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3988 conf_tid->apsd_conf[0] = 0;
3989 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003990 goto out;
3991 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003992
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003993 ret = wl1271_ps_elp_wakeup(wl);
3994 if (ret < 0)
3995 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003996
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003997 /*
3998 * the txop is confed in units of 32us by the mac80211,
3999 * we need us
4000 */
Eliad Peller0603d892011-10-05 11:55:51 +02004001 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004002 params->cw_min, params->cw_max,
4003 params->aifs, params->txop << 5);
4004 if (ret < 0)
4005 goto out_sleep;
4006
Eliad Peller0603d892011-10-05 11:55:51 +02004007 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004008 CONF_CHANNEL_TYPE_EDCF,
4009 wl1271_tx_get_queue(queue),
4010 ps_scheme, CONF_ACK_POLICY_LEGACY,
4011 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004012
4013out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004014 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004015
4016out:
4017 mutex_unlock(&wl->mutex);
4018
4019 return ret;
4020}
4021
Eliad Peller37a41b42011-09-21 14:06:11 +03004022static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4023 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004024{
4025
4026 struct wl1271 *wl = hw->priv;
4027 u64 mactime = ULLONG_MAX;
4028 int ret;
4029
4030 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4031
4032 mutex_lock(&wl->mutex);
4033
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004034 if (unlikely(wl->state == WL1271_STATE_OFF))
4035 goto out;
4036
Ido Yariva6208652011-03-01 15:14:41 +02004037 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004038 if (ret < 0)
4039 goto out;
4040
4041 ret = wl1271_acx_tsf_info(wl, &mactime);
4042 if (ret < 0)
4043 goto out_sleep;
4044
4045out_sleep:
4046 wl1271_ps_elp_sleep(wl);
4047
4048out:
4049 mutex_unlock(&wl->mutex);
4050 return mactime;
4051}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004052
John W. Linvilleece550d2010-07-28 16:41:06 -04004053static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4054 struct survey_info *survey)
4055{
4056 struct wl1271 *wl = hw->priv;
4057 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004058
John W. Linvilleece550d2010-07-28 16:41:06 -04004059 if (idx != 0)
4060 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004061
John W. Linvilleece550d2010-07-28 16:41:06 -04004062 survey->channel = conf->channel;
4063 survey->filled = SURVEY_INFO_NOISE_DBM;
4064 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004065
John W. Linvilleece550d2010-07-28 16:41:06 -04004066 return 0;
4067}
4068
Arik Nemtsov409622e2011-02-23 00:22:29 +02004069static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004070 struct wl12xx_vif *wlvif,
4071 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004072{
4073 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004074 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004075
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004076
4077 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004078 wl1271_warning("could not allocate HLID - too much stations");
4079 return -EBUSY;
4080 }
4081
4082 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004083 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4084 if (ret < 0) {
4085 wl1271_warning("could not allocate HLID - too many links");
4086 return -EBUSY;
4087 }
4088
4089 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004090 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004091 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004092 return 0;
4093}
4094
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004095void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004096{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004097 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004098 return;
4099
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004100 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004101 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004102 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004103 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004104 __clear_bit(hlid, &wl->ap_ps_map);
4105 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004106 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004107 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004108}
4109
4110static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4111 struct ieee80211_vif *vif,
4112 struct ieee80211_sta *sta)
4113{
4114 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004115 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004116 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004117 int ret = 0;
4118 u8 hlid;
4119
4120 mutex_lock(&wl->mutex);
4121
4122 if (unlikely(wl->state == WL1271_STATE_OFF))
4123 goto out;
4124
Eliad Peller536129c2011-10-05 11:55:45 +02004125 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004126 goto out;
4127
4128 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4129
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004130 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004131 if (ret < 0)
4132 goto out;
4133
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004134 wl_sta = (struct wl1271_station *)sta->drv_priv;
4135 hlid = wl_sta->hlid;
4136
Ido Yariva6208652011-03-01 15:14:41 +02004137 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004138 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004139 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004140
Eliad Peller1b92f152011-10-10 10:13:09 +02004141 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004142 if (ret < 0)
4143 goto out_sleep;
4144
Eliad Pellerb67476e2011-08-14 13:17:23 +03004145 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4146 if (ret < 0)
4147 goto out_sleep;
4148
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004149 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4150 if (ret < 0)
4151 goto out_sleep;
4152
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004153out_sleep:
4154 wl1271_ps_elp_sleep(wl);
4155
Arik Nemtsov409622e2011-02-23 00:22:29 +02004156out_free_sta:
4157 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004158 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004159
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004160out:
4161 mutex_unlock(&wl->mutex);
4162 return ret;
4163}
4164
4165static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4166 struct ieee80211_vif *vif,
4167 struct ieee80211_sta *sta)
4168{
4169 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004170 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004171 struct wl1271_station *wl_sta;
4172 int ret = 0, id;
4173
4174 mutex_lock(&wl->mutex);
4175
4176 if (unlikely(wl->state == WL1271_STATE_OFF))
4177 goto out;
4178
Eliad Peller536129c2011-10-05 11:55:45 +02004179 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004180 goto out;
4181
4182 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4183
4184 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004185 id = wl_sta->hlid;
4186 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004187 goto out;
4188
Ido Yariva6208652011-03-01 15:14:41 +02004189 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004190 if (ret < 0)
4191 goto out;
4192
Eliad Pellerc690ec82011-08-14 13:17:07 +03004193 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004194 if (ret < 0)
4195 goto out_sleep;
4196
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004197 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004198
4199out_sleep:
4200 wl1271_ps_elp_sleep(wl);
4201
4202out:
4203 mutex_unlock(&wl->mutex);
4204 return ret;
4205}
4206
Luciano Coelho4623ec72011-03-21 19:26:41 +02004207static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4208 struct ieee80211_vif *vif,
4209 enum ieee80211_ampdu_mlme_action action,
4210 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4211 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004212{
4213 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004214 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004215 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004216 u8 hlid, *ba_bitmap;
4217
4218 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4219 tid);
4220
4221 /* sanity check - the fields in FW are only 8bits wide */
4222 if (WARN_ON(tid > 0xFF))
4223 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004224
4225 mutex_lock(&wl->mutex);
4226
4227 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4228 ret = -EAGAIN;
4229 goto out;
4230 }
4231
Eliad Peller536129c2011-10-05 11:55:45 +02004232 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004233 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004234 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004235 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004236 struct wl1271_station *wl_sta;
4237
4238 wl_sta = (struct wl1271_station *)sta->drv_priv;
4239 hlid = wl_sta->hlid;
4240 ba_bitmap = &wl->links[hlid].ba_bitmap;
4241 } else {
4242 ret = -EINVAL;
4243 goto out;
4244 }
4245
Ido Yariva6208652011-03-01 15:14:41 +02004246 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004247 if (ret < 0)
4248 goto out;
4249
Shahar Levi70559a02011-05-22 16:10:22 +03004250 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4251 tid, action);
4252
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004253 switch (action) {
4254 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004255 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004256 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004257 break;
4258 }
4259
4260 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4261 ret = -EBUSY;
4262 wl1271_error("exceeded max RX BA sessions");
4263 break;
4264 }
4265
4266 if (*ba_bitmap & BIT(tid)) {
4267 ret = -EINVAL;
4268 wl1271_error("cannot enable RX BA session on active "
4269 "tid: %d", tid);
4270 break;
4271 }
4272
4273 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4274 hlid);
4275 if (!ret) {
4276 *ba_bitmap |= BIT(tid);
4277 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004278 }
4279 break;
4280
4281 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004282 if (!(*ba_bitmap & BIT(tid))) {
4283 ret = -EINVAL;
4284 wl1271_error("no active RX BA session on tid: %d",
4285 tid);
4286 break;
4287 }
4288
4289 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4290 hlid);
4291 if (!ret) {
4292 *ba_bitmap &= ~BIT(tid);
4293 wl->ba_rx_session_count--;
4294 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004295 break;
4296
4297 /*
4298 * The BA initiator session management in FW independently.
4299 * Falling break here on purpose for all TX APDU commands.
4300 */
4301 case IEEE80211_AMPDU_TX_START:
4302 case IEEE80211_AMPDU_TX_STOP:
4303 case IEEE80211_AMPDU_TX_OPERATIONAL:
4304 ret = -EINVAL;
4305 break;
4306
4307 default:
4308 wl1271_error("Incorrect ampdu action id=%x\n", action);
4309 ret = -EINVAL;
4310 }
4311
4312 wl1271_ps_elp_sleep(wl);
4313
4314out:
4315 mutex_unlock(&wl->mutex);
4316
4317 return ret;
4318}
4319
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004320static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4321 struct ieee80211_vif *vif,
4322 const struct cfg80211_bitrate_mask *mask)
4323{
Eliad Peller83587502011-10-10 10:12:53 +02004324 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004325 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004326 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004327
4328 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4329 mask->control[NL80211_BAND_2GHZ].legacy,
4330 mask->control[NL80211_BAND_5GHZ].legacy);
4331
4332 mutex_lock(&wl->mutex);
4333
4334 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004335 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004336 wl1271_tx_enabled_rates_get(wl,
4337 mask->control[i].legacy,
4338 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004339
4340 if (unlikely(wl->state == WL1271_STATE_OFF))
4341 goto out;
4342
4343 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4344 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4345
4346 ret = wl1271_ps_elp_wakeup(wl);
4347 if (ret < 0)
4348 goto out;
4349
4350 wl1271_set_band_rate(wl, wlvif);
4351 wlvif->basic_rate =
4352 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4353 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4354
4355 wl1271_ps_elp_sleep(wl);
4356 }
4357out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004358 mutex_unlock(&wl->mutex);
4359
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004360 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004361}
4362
Shahar Levi6d158ff2011-09-08 13:01:33 +03004363static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4364 struct ieee80211_channel_switch *ch_switch)
4365{
4366 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004367 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004368 int ret;
4369
4370 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4371
4372 mutex_lock(&wl->mutex);
4373
4374 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004375 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4376 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4377 ieee80211_chswitch_done(vif, false);
4378 }
4379 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004380 }
4381
4382 ret = wl1271_ps_elp_wakeup(wl);
4383 if (ret < 0)
4384 goto out;
4385
Eliad Peller52630c52011-10-10 10:13:08 +02004386 /* TODO: change mac80211 to pass vif as param */
4387 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4388 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004389
Eliad Peller52630c52011-10-10 10:13:08 +02004390 if (!ret)
4391 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4392 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004393
4394 wl1271_ps_elp_sleep(wl);
4395
4396out:
4397 mutex_unlock(&wl->mutex);
4398}
4399
Arik Nemtsov33437892011-04-26 23:35:39 +03004400static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4401{
4402 struct wl1271 *wl = hw->priv;
4403 bool ret = false;
4404
4405 mutex_lock(&wl->mutex);
4406
4407 if (unlikely(wl->state == WL1271_STATE_OFF))
4408 goto out;
4409
4410 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004411 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004412out:
4413 mutex_unlock(&wl->mutex);
4414
4415 return ret;
4416}
4417
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004418/* can't be const, mac80211 writes to this */
4419static struct ieee80211_rate wl1271_rates[] = {
4420 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004421 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4422 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004423 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004424 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4425 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004426 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4427 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004428 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4429 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004430 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4431 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004432 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4433 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004434 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4435 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004436 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4437 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004438 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004439 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4440 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004441 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004442 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4443 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004444 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004445 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4446 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004447 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004448 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4449 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004450 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004451 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4452 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004453 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004454 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4455 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004456 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004457 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4458 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004459};
4460
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004461/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004462static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004463 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004464 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004465 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4466 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4467 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004468 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004469 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4470 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4471 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004472 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004473 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4474 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4475 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004476 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004477};
4478
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004479/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004480static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004481 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004482 7, /* CONF_HW_RXTX_RATE_MCS7 */
4483 6, /* CONF_HW_RXTX_RATE_MCS6 */
4484 5, /* CONF_HW_RXTX_RATE_MCS5 */
4485 4, /* CONF_HW_RXTX_RATE_MCS4 */
4486 3, /* CONF_HW_RXTX_RATE_MCS3 */
4487 2, /* CONF_HW_RXTX_RATE_MCS2 */
4488 1, /* CONF_HW_RXTX_RATE_MCS1 */
4489 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004490
4491 11, /* CONF_HW_RXTX_RATE_54 */
4492 10, /* CONF_HW_RXTX_RATE_48 */
4493 9, /* CONF_HW_RXTX_RATE_36 */
4494 8, /* CONF_HW_RXTX_RATE_24 */
4495
4496 /* TI-specific rate */
4497 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4498
4499 7, /* CONF_HW_RXTX_RATE_18 */
4500 6, /* CONF_HW_RXTX_RATE_12 */
4501 3, /* CONF_HW_RXTX_RATE_11 */
4502 5, /* CONF_HW_RXTX_RATE_9 */
4503 4, /* CONF_HW_RXTX_RATE_6 */
4504 2, /* CONF_HW_RXTX_RATE_5_5 */
4505 1, /* CONF_HW_RXTX_RATE_2 */
4506 0 /* CONF_HW_RXTX_RATE_1 */
4507};
4508
Shahar Levie8b03a22010-10-13 16:09:39 +02004509/* 11n STA capabilities */
4510#define HW_RX_HIGHEST_RATE 72
4511
Shahar Levi00d20102010-11-08 11:20:10 +00004512#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004513 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4514 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004515 .ht_supported = true, \
4516 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4517 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4518 .mcs = { \
4519 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4520 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4521 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4522 }, \
4523}
4524
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004525/* can't be const, mac80211 writes to this */
4526static struct ieee80211_supported_band wl1271_band_2ghz = {
4527 .channels = wl1271_channels,
4528 .n_channels = ARRAY_SIZE(wl1271_channels),
4529 .bitrates = wl1271_rates,
4530 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004531 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004532};
4533
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004534/* 5 GHz data rates for WL1273 */
4535static struct ieee80211_rate wl1271_rates_5ghz[] = {
4536 { .bitrate = 60,
4537 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4538 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4539 { .bitrate = 90,
4540 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4541 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4542 { .bitrate = 120,
4543 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4544 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4545 { .bitrate = 180,
4546 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4547 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4548 { .bitrate = 240,
4549 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4550 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4551 { .bitrate = 360,
4552 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4553 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4554 { .bitrate = 480,
4555 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4556 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4557 { .bitrate = 540,
4558 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4559 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4560};
4561
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004562/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004563static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004564 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4565 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4566 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4567 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4568 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4569 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4570 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4571 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4572 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4573 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4574 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4575 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4576 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4577 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4578 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4579 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4580 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4581 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4582 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4583 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4584 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4585 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4586 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4587 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4588 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4589 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4590 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4591 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4592 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4593 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4594 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4595 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4596 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4597 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004598};
4599
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004600/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004601static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004602 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004603 7, /* CONF_HW_RXTX_RATE_MCS7 */
4604 6, /* CONF_HW_RXTX_RATE_MCS6 */
4605 5, /* CONF_HW_RXTX_RATE_MCS5 */
4606 4, /* CONF_HW_RXTX_RATE_MCS4 */
4607 3, /* CONF_HW_RXTX_RATE_MCS3 */
4608 2, /* CONF_HW_RXTX_RATE_MCS2 */
4609 1, /* CONF_HW_RXTX_RATE_MCS1 */
4610 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004611
4612 7, /* CONF_HW_RXTX_RATE_54 */
4613 6, /* CONF_HW_RXTX_RATE_48 */
4614 5, /* CONF_HW_RXTX_RATE_36 */
4615 4, /* CONF_HW_RXTX_RATE_24 */
4616
4617 /* TI-specific rate */
4618 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4619
4620 3, /* CONF_HW_RXTX_RATE_18 */
4621 2, /* CONF_HW_RXTX_RATE_12 */
4622 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4623 1, /* CONF_HW_RXTX_RATE_9 */
4624 0, /* CONF_HW_RXTX_RATE_6 */
4625 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4626 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4627 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4628};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004629
4630static struct ieee80211_supported_band wl1271_band_5ghz = {
4631 .channels = wl1271_channels_5ghz,
4632 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4633 .bitrates = wl1271_rates_5ghz,
4634 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004635 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004636};
4637
Tobias Klausera0ea9492010-05-20 10:38:11 +02004638static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004639 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4640 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4641};
4642
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004643static const struct ieee80211_ops wl1271_ops = {
4644 .start = wl1271_op_start,
4645 .stop = wl1271_op_stop,
4646 .add_interface = wl1271_op_add_interface,
4647 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004648#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004649 .suspend = wl1271_op_suspend,
4650 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004651#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004652 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004653 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004654 .configure_filter = wl1271_op_configure_filter,
4655 .tx = wl1271_op_tx,
4656 .set_key = wl1271_op_set_key,
4657 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004658 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004659 .sched_scan_start = wl1271_op_sched_scan_start,
4660 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004661 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004662 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004663 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004664 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004665 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004666 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004667 .sta_add = wl1271_op_sta_add,
4668 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004669 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004670 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004671 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004672 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004673 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004674};
4675
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004676
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004677u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004678{
4679 u8 idx;
4680
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004681 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004682
4683 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4684 wl1271_error("Illegal RX rate from HW: %d", rate);
4685 return 0;
4686 }
4687
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004688 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004689 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4690 wl1271_error("Unsupported RX rate from HW: %d", rate);
4691 return 0;
4692 }
4693
4694 return idx;
4695}
4696
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004697static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4698 struct device_attribute *attr,
4699 char *buf)
4700{
4701 struct wl1271 *wl = dev_get_drvdata(dev);
4702 ssize_t len;
4703
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004704 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004705
4706 mutex_lock(&wl->mutex);
4707 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4708 wl->sg_enabled);
4709 mutex_unlock(&wl->mutex);
4710
4711 return len;
4712
4713}
4714
4715static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4716 struct device_attribute *attr,
4717 const char *buf, size_t count)
4718{
4719 struct wl1271 *wl = dev_get_drvdata(dev);
4720 unsigned long res;
4721 int ret;
4722
Luciano Coelho6277ed62011-04-01 17:49:54 +03004723 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004724 if (ret < 0) {
4725 wl1271_warning("incorrect value written to bt_coex_mode");
4726 return count;
4727 }
4728
4729 mutex_lock(&wl->mutex);
4730
4731 res = !!res;
4732
4733 if (res == wl->sg_enabled)
4734 goto out;
4735
4736 wl->sg_enabled = res;
4737
4738 if (wl->state == WL1271_STATE_OFF)
4739 goto out;
4740
Ido Yariva6208652011-03-01 15:14:41 +02004741 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004742 if (ret < 0)
4743 goto out;
4744
4745 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4746 wl1271_ps_elp_sleep(wl);
4747
4748 out:
4749 mutex_unlock(&wl->mutex);
4750 return count;
4751}
4752
4753static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4754 wl1271_sysfs_show_bt_coex_state,
4755 wl1271_sysfs_store_bt_coex_state);
4756
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004757static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4758 struct device_attribute *attr,
4759 char *buf)
4760{
4761 struct wl1271 *wl = dev_get_drvdata(dev);
4762 ssize_t len;
4763
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004764 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004765
4766 mutex_lock(&wl->mutex);
4767 if (wl->hw_pg_ver >= 0)
4768 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4769 else
4770 len = snprintf(buf, len, "n/a\n");
4771 mutex_unlock(&wl->mutex);
4772
4773 return len;
4774}
4775
Gery Kahn6f07b722011-07-18 14:21:49 +03004776static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004777 wl1271_sysfs_show_hw_pg_ver, NULL);
4778
Ido Yariv95dac04f2011-06-06 14:57:06 +03004779static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4780 struct bin_attribute *bin_attr,
4781 char *buffer, loff_t pos, size_t count)
4782{
4783 struct device *dev = container_of(kobj, struct device, kobj);
4784 struct wl1271 *wl = dev_get_drvdata(dev);
4785 ssize_t len;
4786 int ret;
4787
4788 ret = mutex_lock_interruptible(&wl->mutex);
4789 if (ret < 0)
4790 return -ERESTARTSYS;
4791
4792 /* Let only one thread read the log at a time, blocking others */
4793 while (wl->fwlog_size == 0) {
4794 DEFINE_WAIT(wait);
4795
4796 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4797 &wait,
4798 TASK_INTERRUPTIBLE);
4799
4800 if (wl->fwlog_size != 0) {
4801 finish_wait(&wl->fwlog_waitq, &wait);
4802 break;
4803 }
4804
4805 mutex_unlock(&wl->mutex);
4806
4807 schedule();
4808 finish_wait(&wl->fwlog_waitq, &wait);
4809
4810 if (signal_pending(current))
4811 return -ERESTARTSYS;
4812
4813 ret = mutex_lock_interruptible(&wl->mutex);
4814 if (ret < 0)
4815 return -ERESTARTSYS;
4816 }
4817
4818 /* Check if the fwlog is still valid */
4819 if (wl->fwlog_size < 0) {
4820 mutex_unlock(&wl->mutex);
4821 return 0;
4822 }
4823
4824 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4825 len = min(count, (size_t)wl->fwlog_size);
4826 wl->fwlog_size -= len;
4827 memcpy(buffer, wl->fwlog, len);
4828
4829 /* Make room for new messages */
4830 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4831
4832 mutex_unlock(&wl->mutex);
4833
4834 return len;
4835}
4836
4837static struct bin_attribute fwlog_attr = {
4838 .attr = {.name = "fwlog", .mode = S_IRUSR},
4839 .read = wl1271_sysfs_read_fwlog,
4840};
4841
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004842static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004843{
4844 int ret;
4845
4846 if (wl->mac80211_registered)
4847 return 0;
4848
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004849 ret = wl1271_fetch_nvs(wl);
4850 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004851 /* NOTE: The wl->nvs->nvs element must be first, in
4852 * order to simplify the casting, we assume it is at
4853 * the beginning of the wl->nvs structure.
4854 */
4855 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004856
4857 wl->mac_addr[0] = nvs_ptr[11];
4858 wl->mac_addr[1] = nvs_ptr[10];
4859 wl->mac_addr[2] = nvs_ptr[6];
4860 wl->mac_addr[3] = nvs_ptr[5];
4861 wl->mac_addr[4] = nvs_ptr[4];
4862 wl->mac_addr[5] = nvs_ptr[3];
4863 }
4864
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004865 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4866
4867 ret = ieee80211_register_hw(wl->hw);
4868 if (ret < 0) {
4869 wl1271_error("unable to register mac80211 hw: %d", ret);
4870 return ret;
4871 }
4872
4873 wl->mac80211_registered = true;
4874
Eliad Pellerd60080a2010-11-24 12:53:16 +02004875 wl1271_debugfs_init(wl);
4876
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004877 register_netdevice_notifier(&wl1271_dev_notifier);
4878
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004879 wl1271_notice("loaded");
4880
4881 return 0;
4882}
4883
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004884static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004885{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004886 if (wl->state == WL1271_STATE_PLT)
4887 __wl1271_plt_stop(wl);
4888
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004889 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004890 ieee80211_unregister_hw(wl->hw);
4891 wl->mac80211_registered = false;
4892
4893}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004894
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004895static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004896{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004897 static const u32 cipher_suites[] = {
4898 WLAN_CIPHER_SUITE_WEP40,
4899 WLAN_CIPHER_SUITE_WEP104,
4900 WLAN_CIPHER_SUITE_TKIP,
4901 WLAN_CIPHER_SUITE_CCMP,
4902 WL1271_CIPHER_SUITE_GEM,
4903 };
4904
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004905 /* The tx descriptor buffer and the TKIP space. */
4906 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4907 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004908
4909 /* unit us */
4910 /* FIXME: find a proper value */
4911 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004912 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004913
4914 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004915 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004916 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004917 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004918 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004919 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004920 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004921 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004922 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004923 IEEE80211_HW_AP_LINK_PS |
4924 IEEE80211_HW_AMPDU_AGGREGATION |
4925 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004926
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004927 wl->hw->wiphy->cipher_suites = cipher_suites;
4928 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4929
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004930 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004931 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4932 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004933 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004934 wl->hw->wiphy->max_sched_scan_ssids = 16;
4935 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004936 /*
4937 * Maximum length of elements in scanning probe request templates
4938 * should be the maximum length possible for a template, without
4939 * the IEEE80211 header of the template
4940 */
Eliad Peller154037d2011-08-14 13:17:12 +03004941 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004942 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004943
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004944 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4945 sizeof(struct ieee80211_header);
4946
Eliad Peller1ec23f72011-08-25 14:26:54 +03004947 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4948
Luciano Coelho4a31c112011-03-21 23:16:14 +02004949 /* make sure all our channels fit in the scanned_ch bitmask */
4950 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4951 ARRAY_SIZE(wl1271_channels_5ghz) >
4952 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004953 /*
4954 * We keep local copies of the band structs because we need to
4955 * modify them on a per-device basis.
4956 */
4957 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4958 sizeof(wl1271_band_2ghz));
4959 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4960 sizeof(wl1271_band_5ghz));
4961
4962 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4963 &wl->bands[IEEE80211_BAND_2GHZ];
4964 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4965 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004966
Kalle Valo12bd8942010-03-18 12:26:33 +02004967 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004968 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004969
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004970 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4971
Felipe Balbia390e852011-10-06 10:07:44 +03004972 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004973
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004974 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004975 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004976
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004977 wl->hw->max_rx_aggregation_subframes = 8;
4978
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004979 return 0;
4980}
4981
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004982#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004983
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004984static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004985{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004986 struct ieee80211_hw *hw;
4987 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004988 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004989 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004990
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004991 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004992
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004993 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4994 if (!hw) {
4995 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004996 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004997 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004998 }
4999
5000 wl = hw->priv;
5001 memset(wl, 0, sizeof(*wl));
5002
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005003 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005004 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005005
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005006 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005007
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005008 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005009 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005010 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5011
Ido Yariva6208652011-03-01 15:14:41 +02005012 skb_queue_head_init(&wl->deferred_rx_queue);
5013 skb_queue_head_init(&wl->deferred_tx_queue);
5014
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005015 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005016 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005017 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5018 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5019 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005020
Eliad Peller92ef8962011-06-07 12:50:46 +03005021 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5022 if (!wl->freezable_wq) {
5023 ret = -ENOMEM;
5024 goto err_hw;
5025 }
5026
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005027 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005028 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005029 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005030 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005031 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005032 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005033 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005034 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005035 wl->ap_ps_map = 0;
5036 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005037 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005038 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005039 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005040 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005041 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005042 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005043 wl->fwlog_size = 0;
5044 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005045
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005046 /* The system link is always allocated */
5047 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5048
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005049 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005050 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005051 wl->tx_frames[i] = NULL;
5052
5053 spin_lock_init(&wl->wl_lock);
5054
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005055 wl->state = WL1271_STATE_OFF;
5056 mutex_init(&wl->mutex);
5057
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005058 /* Apply default driver configuration. */
5059 wl1271_conf_init(wl);
5060
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005061 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5062 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5063 if (!wl->aggr_buf) {
5064 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005065 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005066 }
5067
Ido Yariv990f5de2011-03-31 10:06:59 +02005068 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5069 if (!wl->dummy_packet) {
5070 ret = -ENOMEM;
5071 goto err_aggr;
5072 }
5073
Ido Yariv95dac04f2011-06-06 14:57:06 +03005074 /* Allocate one page for the FW log */
5075 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5076 if (!wl->fwlog) {
5077 ret = -ENOMEM;
5078 goto err_dummy_packet;
5079 }
5080
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005081 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005082
Ido Yariv990f5de2011-03-31 10:06:59 +02005083err_dummy_packet:
5084 dev_kfree_skb(wl->dummy_packet);
5085
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005086err_aggr:
5087 free_pages((unsigned long)wl->aggr_buf, order);
5088
Eliad Peller92ef8962011-06-07 12:50:46 +03005089err_wq:
5090 destroy_workqueue(wl->freezable_wq);
5091
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005092err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005093 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005094 ieee80211_free_hw(hw);
5095
5096err_hw_alloc:
5097
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005098 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005099}
5100
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005101static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005102{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005103 /* Unblock any fwlog readers */
5104 mutex_lock(&wl->mutex);
5105 wl->fwlog_size = -1;
5106 wake_up_interruptible_all(&wl->fwlog_waitq);
5107 mutex_unlock(&wl->mutex);
5108
Felipe Balbif79f8902011-10-06 13:05:25 +03005109 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005110
Felipe Balbif79f8902011-10-06 13:05:25 +03005111 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005112
Felipe Balbif79f8902011-10-06 13:05:25 +03005113 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005114 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005115 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005116 free_pages((unsigned long)wl->aggr_buf,
5117 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005118
5119 wl1271_debugfs_exit(wl);
5120
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005121 vfree(wl->fw);
5122 wl->fw = NULL;
5123 kfree(wl->nvs);
5124 wl->nvs = NULL;
5125
5126 kfree(wl->fw_status);
5127 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005128 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005129
5130 ieee80211_free_hw(wl->hw);
5131
5132 return 0;
5133}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005134
Felipe Balbia390e852011-10-06 10:07:44 +03005135static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5136{
5137 struct wl1271 *wl = cookie;
5138 unsigned long flags;
5139
5140 wl1271_debug(DEBUG_IRQ, "IRQ");
5141
5142 /* complete the ELP completion */
5143 spin_lock_irqsave(&wl->wl_lock, flags);
5144 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5145 if (wl->elp_compl) {
5146 complete(wl->elp_compl);
5147 wl->elp_compl = NULL;
5148 }
5149
5150 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5151 /* don't enqueue a work right now. mark it as pending */
5152 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5153 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5154 disable_irq_nosync(wl->irq);
5155 pm_wakeup_event(wl->dev, 0);
5156 spin_unlock_irqrestore(&wl->wl_lock, flags);
5157 return IRQ_HANDLED;
5158 }
5159 spin_unlock_irqrestore(&wl->wl_lock, flags);
5160
5161 return IRQ_WAKE_THREAD;
5162}
5163
Felipe Balbice2a2172011-10-05 14:12:55 +03005164static int __devinit wl12xx_probe(struct platform_device *pdev)
5165{
Felipe Balbia390e852011-10-06 10:07:44 +03005166 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5167 struct ieee80211_hw *hw;
5168 struct wl1271 *wl;
5169 unsigned long irqflags;
5170 int ret = -ENODEV;
5171
5172 hw = wl1271_alloc_hw();
5173 if (IS_ERR(hw)) {
5174 wl1271_error("can't allocate hw");
5175 ret = PTR_ERR(hw);
5176 goto out;
5177 }
5178
5179 wl = hw->priv;
5180 wl->irq = platform_get_irq(pdev, 0);
5181 wl->ref_clock = pdata->board_ref_clock;
5182 wl->tcxo_clock = pdata->board_tcxo_clock;
5183 wl->platform_quirks = pdata->platform_quirks;
5184 wl->set_power = pdata->set_power;
5185 wl->dev = &pdev->dev;
5186 wl->if_ops = pdata->ops;
5187
5188 platform_set_drvdata(pdev, wl);
5189
5190 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5191 irqflags = IRQF_TRIGGER_RISING;
5192 else
5193 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5194
5195 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5196 irqflags,
5197 pdev->name, wl);
5198 if (ret < 0) {
5199 wl1271_error("request_irq() failed: %d", ret);
5200 goto out_free_hw;
5201 }
5202
5203 ret = enable_irq_wake(wl->irq);
5204 if (!ret) {
5205 wl->irq_wake_enabled = true;
5206 device_init_wakeup(wl->dev, 1);
5207 if (pdata->pwr_in_suspend)
5208 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5209
5210 }
5211 disable_irq(wl->irq);
5212
5213 ret = wl1271_init_ieee80211(wl);
5214 if (ret)
5215 goto out_irq;
5216
5217 ret = wl1271_register_hw(wl);
5218 if (ret)
5219 goto out_irq;
5220
Felipe Balbif79f8902011-10-06 13:05:25 +03005221 /* Create sysfs file to control bt coex state */
5222 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5223 if (ret < 0) {
5224 wl1271_error("failed to create sysfs file bt_coex_state");
5225 goto out_irq;
5226 }
5227
5228 /* Create sysfs file to get HW PG version */
5229 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5230 if (ret < 0) {
5231 wl1271_error("failed to create sysfs file hw_pg_ver");
5232 goto out_bt_coex_state;
5233 }
5234
5235 /* Create sysfs file for the FW log */
5236 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5237 if (ret < 0) {
5238 wl1271_error("failed to create sysfs file fwlog");
5239 goto out_hw_pg_ver;
5240 }
5241
Felipe Balbice2a2172011-10-05 14:12:55 +03005242 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005243
Felipe Balbif79f8902011-10-06 13:05:25 +03005244out_hw_pg_ver:
5245 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5246
5247out_bt_coex_state:
5248 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5249
Felipe Balbia390e852011-10-06 10:07:44 +03005250out_irq:
5251 free_irq(wl->irq, wl);
5252
5253out_free_hw:
5254 wl1271_free_hw(wl);
5255
5256out:
5257 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005258}
5259
5260static int __devexit wl12xx_remove(struct platform_device *pdev)
5261{
Felipe Balbia390e852011-10-06 10:07:44 +03005262 struct wl1271 *wl = platform_get_drvdata(pdev);
5263
5264 if (wl->irq_wake_enabled) {
5265 device_init_wakeup(wl->dev, 0);
5266 disable_irq_wake(wl->irq);
5267 }
5268 wl1271_unregister_hw(wl);
5269 free_irq(wl->irq, wl);
5270 wl1271_free_hw(wl);
5271
Felipe Balbice2a2172011-10-05 14:12:55 +03005272 return 0;
5273}
5274
5275static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005276 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005277 { } /* Terminating Entry */
5278};
5279MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5280
5281static struct platform_driver wl12xx_driver = {
5282 .probe = wl12xx_probe,
5283 .remove = __devexit_p(wl12xx_remove),
5284 .id_table = wl12xx_id_table,
5285 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005286 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005287 .owner = THIS_MODULE,
5288 }
5289};
5290
5291static int __init wl12xx_init(void)
5292{
5293 return platform_driver_register(&wl12xx_driver);
5294}
5295module_init(wl12xx_init);
5296
5297static void __exit wl12xx_exit(void)
5298{
5299 platform_driver_unregister(&wl12xx_driver);
5300}
5301module_exit(wl12xx_exit);
5302
Guy Eilam491bbd62011-01-12 10:33:29 +01005303u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005304EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005305module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005306MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5307
Ido Yariv95dac04f2011-06-06 14:57:06 +03005308module_param_named(fwlog, fwlog_param, charp, 0);
5309MODULE_PARM_DESC(keymap,
5310 "FW logger options: continuous, ondemand, dbgpins or disable");
5311
Eliad Peller2a5bff02011-08-25 18:10:59 +03005312module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5313MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5314
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005315MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005316MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005317MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");