blob: bba2a52256b601e08724d3577b3a20e5e74b600e [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 Peller6ab70912011-12-18 20:25:45 +0200453 if (dev->operstate != IF_OPER_UP)
454 goto out;
455 /*
456 * The correct behavior should be just getting the appropriate wlvif
457 * from the given dev, but currently we don't have a mac80211
458 * interface for it.
459 */
Eliad Pellerba8447f2011-10-10 10:13:00 +0200460 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller6ab70912011-12-18 20:25:45 +0200461 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
462
Eliad Pellerba8447f2011-10-10 10:13:00 +0200463 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
464 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300465
Eliad Pellerba8447f2011-10-10 10:13:00 +0200466 ret = wl1271_ps_elp_wakeup(wl);
467 if (ret < 0)
468 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300469
Eliad Peller6ab70912011-12-18 20:25:45 +0200470 wl1271_check_operstate(wl, wlvif,
471 ieee80211_get_operstate(vif));
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300472
Eliad Pellerba8447f2011-10-10 10:13:00 +0200473 wl1271_ps_elp_sleep(wl);
474 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300475out:
476 mutex_unlock(&wl->mutex);
477
478 return NOTIFY_OK;
479}
480
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100481static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200482 struct regulatory_request *request)
483{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100484 struct ieee80211_supported_band *band;
485 struct ieee80211_channel *ch;
486 int i;
487
488 band = wiphy->bands[IEEE80211_BAND_5GHZ];
489 for (i = 0; i < band->n_channels; i++) {
490 ch = &band->channels[i];
491 if (ch->flags & IEEE80211_CHAN_DISABLED)
492 continue;
493
494 if (ch->flags & IEEE80211_CHAN_RADAR)
495 ch->flags |= IEEE80211_CHAN_NO_IBSS |
496 IEEE80211_CHAN_PASSIVE_SCAN;
497
498 }
499
500 return 0;
501}
502
Eliad Peller9eb599e2011-10-10 10:12:59 +0200503static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
504 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300505{
506 int ret = 0;
507
508 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200509 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300510 if (ret < 0)
511 goto out;
512
513 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200514 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300515 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200516 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300517out:
518 return ret;
519}
520
521/*
522 * this function is being called when the rx_streaming interval
523 * has beed changed or rx_streaming should be disabled
524 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200525int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300526{
527 int ret = 0;
528 int period = wl->conf.rx_streaming.interval;
529
530 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200531 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300532 goto out;
533
534 /* reconfigure/disable according to new streaming_period */
535 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200536 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300537 (wl->conf.rx_streaming.always ||
538 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200539 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300540 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200541 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300542 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200543 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300544 }
545out:
546 return ret;
547}
548
549static void wl1271_rx_streaming_enable_work(struct work_struct *work)
550{
551 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200552 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
553 rx_streaming_enable_work);
554 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300555
556 mutex_lock(&wl->mutex);
557
Eliad Peller0744bdb2011-10-10 10:13:05 +0200558 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200559 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300560 (!wl->conf.rx_streaming.always &&
561 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
562 goto out;
563
564 if (!wl->conf.rx_streaming.interval)
565 goto out;
566
567 ret = wl1271_ps_elp_wakeup(wl);
568 if (ret < 0)
569 goto out;
570
Eliad Peller9eb599e2011-10-10 10:12:59 +0200571 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300572 if (ret < 0)
573 goto out_sleep;
574
575 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200576 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300577 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
578
579out_sleep:
580 wl1271_ps_elp_sleep(wl);
581out:
582 mutex_unlock(&wl->mutex);
583}
584
585static void wl1271_rx_streaming_disable_work(struct work_struct *work)
586{
587 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200588 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
589 rx_streaming_disable_work);
590 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300591
592 mutex_lock(&wl->mutex);
593
Eliad Peller0744bdb2011-10-10 10:13:05 +0200594 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300595 goto out;
596
597 ret = wl1271_ps_elp_wakeup(wl);
598 if (ret < 0)
599 goto out;
600
Eliad Peller9eb599e2011-10-10 10:12:59 +0200601 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300602 if (ret)
603 goto out_sleep;
604
605out_sleep:
606 wl1271_ps_elp_sleep(wl);
607out:
608 mutex_unlock(&wl->mutex);
609}
610
611static void wl1271_rx_streaming_timer(unsigned long data)
612{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200613 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
614 struct wl1271 *wl = wlvif->wl;
615 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300616}
617
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300618static void wl1271_conf_init(struct wl1271 *wl)
619{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300620
621 /*
622 * This function applies the default configuration to the driver. This
623 * function is invoked upon driver load (spi probe.)
624 *
625 * The configuration is stored in a run-time structure in order to
626 * facilitate for run-time adjustment of any of the parameters. Making
627 * changes to the configuration structure will apply the new values on
628 * the next interface up (wl1271_op_start.)
629 */
630
631 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300632 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300633
Ido Yariv95dac04f2011-06-06 14:57:06 +0300634 /* Adjust settings according to optional module parameters */
635 if (fwlog_param) {
636 if (!strcmp(fwlog_param, "continuous")) {
637 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
638 } else if (!strcmp(fwlog_param, "ondemand")) {
639 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
640 } else if (!strcmp(fwlog_param, "dbgpins")) {
641 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
642 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
643 } else if (!strcmp(fwlog_param, "disable")) {
644 wl->conf.fwlog.mem_blocks = 0;
645 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
646 } else {
647 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
648 }
649 }
650}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300651
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300652static int wl1271_plt_init(struct wl1271 *wl)
653{
Eliad Peller188e7f52011-12-06 12:15:06 +0200654 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300655
Shahar Levi49d750ca2011-03-06 16:32:09 +0200656 if (wl->chip.id == CHIP_ID_1283_PG20)
657 ret = wl128x_cmd_general_parms(wl);
658 else
659 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200660 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200661 return ret;
662
Shahar Levi49d750ca2011-03-06 16:32:09 +0200663 if (wl->chip.id == CHIP_ID_1283_PG20)
664 ret = wl128x_cmd_radio_parms(wl);
665 else
666 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200667 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200668 return ret;
669
Shahar Levi49d750ca2011-03-06 16:32:09 +0200670 if (wl->chip.id != CHIP_ID_1283_PG20) {
671 ret = wl1271_cmd_ext_radio_parms(wl);
672 if (ret < 0)
673 return ret;
674 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200675 if (ret < 0)
676 return ret;
677
Shahar Levi48a61472011-03-06 16:32:08 +0200678 /* Chip-specific initializations */
679 ret = wl1271_chip_specific_init(wl);
680 if (ret < 0)
681 return ret;
682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 ret = wl1271_acx_init_mem_config(wl);
684 if (ret < 0)
685 return ret;
686
Eliad Peller7f0979882011-08-14 13:17:06 +0300687 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600688 if (ret < 0)
689 goto out_free_memmap;
690
Luciano Coelho12419cc2010-02-18 13:25:44 +0200691 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200692 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300693 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200694 goto out_free_memmap;
695
696 /* Configure for CAM power saving (ie. always active) */
697 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
698 if (ret < 0)
699 goto out_free_memmap;
700
701 /* configure PM */
702 ret = wl1271_acx_pm_config(wl);
703 if (ret < 0)
704 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300705
706 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200707
708 out_free_memmap:
709 kfree(wl->target_mem_map);
710 wl->target_mem_map = NULL;
711
712 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713}
714
Eliad Peller6e8cd332011-10-10 10:13:13 +0200715static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
716 struct wl12xx_vif *wlvif,
717 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200718{
Arik Nemtsovda032092011-08-25 12:43:15 +0300719 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200720
Arik Nemtsovb622d992011-02-23 00:22:31 +0200721 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300722 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200723
724 /*
725 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300726 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200727 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300728 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200729 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200730
Arik Nemtsovda032092011-08-25 12:43:15 +0300731 /*
732 * Start high-level PS if the STA is asleep with enough blocks in FW.
733 * Make an exception if this is the only connected station. In this
734 * case FW-memory congestion is not a problem.
735 */
736 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200737 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200738}
739
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300740static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200741 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300742 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200743{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200744 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200745 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300746 u8 hlid, cnt;
747
748 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200749
750 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
751 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
752 wl1271_debug(DEBUG_PSM,
753 "link ps prev 0x%x cur 0x%x changed 0x%x",
754 wl->ap_fw_ps_map, cur_fw_ps_map,
755 wl->ap_fw_ps_map ^ cur_fw_ps_map);
756
757 wl->ap_fw_ps_map = cur_fw_ps_map;
758 }
759
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200760 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
761 lnk = &wl->links[hlid];
762 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200763
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200764 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
765 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200766
Eliad Peller6e8cd332011-10-10 10:13:13 +0200767 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
768 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200769 }
770}
771
Eliad Peller4d56ad92011-08-14 13:17:05 +0300772static void wl12xx_fw_status(struct wl1271 *wl,
773 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300774{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200775 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200776 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200777 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300778 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300779 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300780
Eliad Peller4d56ad92011-08-14 13:17:05 +0300781 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200782
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300783 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
784 "drv_rx_counter = %d, tx_results_counter = %d)",
785 status->intr,
786 status->fw_rx_counter,
787 status->drv_rx_counter,
788 status->tx_results_counter);
789
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300790 for (i = 0; i < NUM_TX_QUEUES; i++) {
791 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300792 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300793 (status->tx_released_pkts[i] -
794 wl->tx_pkts_freed[i]) & 0xff;
795
796 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
797 }
798
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300799 /* prevent wrap-around in total blocks counter */
800 if (likely(wl->tx_blocks_freed <=
801 le32_to_cpu(status->total_released_blks)))
802 freed_blocks = le32_to_cpu(status->total_released_blks) -
803 wl->tx_blocks_freed;
804 else
805 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
806 le32_to_cpu(status->total_released_blks);
807
Eliad Peller4d56ad92011-08-14 13:17:05 +0300808 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200809
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300810 wl->tx_allocated_blocks -= freed_blocks;
811
Eliad Peller4d56ad92011-08-14 13:17:05 +0300812 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200813
Eliad Peller4d56ad92011-08-14 13:17:05 +0300814 /*
815 * The FW might change the total number of TX memblocks before
816 * we get a notification about blocks being released. Thus, the
817 * available blocks calculation might yield a temporary result
818 * which is lower than the actual available blocks. Keeping in
819 * mind that only blocks that were allocated can be moved from
820 * TX to RX, tx_blocks_available should never decrease here.
821 */
822 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
823 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300824
Ido Yariva5225502010-10-12 14:49:10 +0200825 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200826 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200827 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828
Eliad Peller4d56ad92011-08-14 13:17:05 +0300829 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200830 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200831 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200832 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300833
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200835 getnstimeofday(&ts);
836 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
837 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300838}
839
Ido Yariva6208652011-03-01 15:14:41 +0200840static void wl1271_flush_deferred_work(struct wl1271 *wl)
841{
842 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200843
Ido Yariva6208652011-03-01 15:14:41 +0200844 /* Pass all received frames to the network stack */
845 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
846 ieee80211_rx_ni(wl->hw, skb);
847
848 /* Return sent skbs to the network stack */
849 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300850 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200851}
852
853static void wl1271_netstack_work(struct work_struct *work)
854{
855 struct wl1271 *wl =
856 container_of(work, struct wl1271, netstack_work);
857
858 do {
859 wl1271_flush_deferred_work(wl);
860 } while (skb_queue_len(&wl->deferred_rx_queue));
861}
862
863#define WL1271_IRQ_MAX_LOOPS 256
864
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300865static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300866{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300867 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300868 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200869 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200870 struct wl1271 *wl = (struct wl1271 *)cookie;
871 bool done = false;
872 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200873 unsigned long flags;
874
875 /* TX might be handled here, avoid redundant work */
876 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
877 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878
Ido Yariv341b7cd2011-03-31 10:07:01 +0200879 /*
880 * In case edge triggered interrupt must be used, we cannot iterate
881 * more than once without introducing race conditions with the hardirq.
882 */
883 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
884 loopcount = 1;
885
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300886 mutex_lock(&wl->mutex);
887
888 wl1271_debug(DEBUG_IRQ, "IRQ work");
889
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200890 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300891 goto out;
892
Ido Yariva6208652011-03-01 15:14:41 +0200893 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300894 if (ret < 0)
895 goto out;
896
Ido Yariva6208652011-03-01 15:14:41 +0200897 while (!done && loopcount--) {
898 /*
899 * In order to avoid a race with the hardirq, clear the flag
900 * before acknowledging the chip. Since the mutex is held,
901 * wl1271_ps_elp_wakeup cannot be called concurrently.
902 */
903 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
904 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200905
Eliad Peller4d56ad92011-08-14 13:17:05 +0300906 wl12xx_fw_status(wl, wl->fw_status);
907 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200908 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200909 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200910 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200911 continue;
912 }
913
Eliad Pellerccc83b02010-10-27 14:09:57 +0200914 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
915 wl1271_error("watchdog interrupt received! "
916 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300917 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200918
919 /* restarting the chip. ignore any other interrupt. */
920 goto out;
921 }
922
Ido Yariva6208652011-03-01 15:14:41 +0200923 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200924 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
925
Eliad Peller4d56ad92011-08-14 13:17:05 +0300926 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200927
Ido Yariva5225502010-10-12 14:49:10 +0200928 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200929 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200930 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300931 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200932 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200933 /*
934 * In order to avoid starvation of the TX path,
935 * call the work function directly.
936 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200937 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200938 } else {
939 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200940 }
941
Ido Yariv8aad2462011-03-01 15:14:38 +0200942 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300943 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200944 (wl->tx_results_count & 0xff))
945 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200946
947 /* Make sure the deferred queues don't get too long */
948 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
949 skb_queue_len(&wl->deferred_rx_queue);
950 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
951 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200952 }
953
954 if (intr & WL1271_ACX_INTR_EVENT_A) {
955 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
956 wl1271_event_handle(wl, 0);
957 }
958
959 if (intr & WL1271_ACX_INTR_EVENT_B) {
960 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
961 wl1271_event_handle(wl, 1);
962 }
963
964 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
965 wl1271_debug(DEBUG_IRQ,
966 "WL1271_ACX_INTR_INIT_COMPLETE");
967
968 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
969 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970 }
971
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972 wl1271_ps_elp_sleep(wl);
973
974out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200975 spin_lock_irqsave(&wl->wl_lock, flags);
976 /* In case TX was not handled here, queue TX work */
977 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
978 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300979 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200980 ieee80211_queue_work(wl->hw, &wl->tx_work);
981 spin_unlock_irqrestore(&wl->wl_lock, flags);
982
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200984
985 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300986}
987
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988static int wl1271_fetch_firmware(struct wl1271 *wl)
989{
990 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200991 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300992 int ret;
993
Arik Nemtsovc302b2c2011-08-17 10:45:48 +0300994 if (wl->chip.id == CHIP_ID_1283_PG20)
995 fw_name = WL128X_FW_NAME;
996 else
997 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200998
999 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1000
Felipe Balbia390e852011-10-06 10:07:44 +03001001 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001002
1003 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001004 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001005 return ret;
1006 }
1007
1008 if (fw->size % 4) {
1009 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1010 fw->size);
1011 ret = -EILSEQ;
1012 goto out;
1013 }
1014
Arik Nemtsov166d5042010-10-16 21:44:57 +02001015 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001017 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018
1019 if (!wl->fw) {
1020 wl1271_error("could not allocate memory for the firmware");
1021 ret = -ENOMEM;
1022 goto out;
1023 }
1024
1025 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026 ret = 0;
1027
1028out:
1029 release_firmware(fw);
1030
1031 return ret;
1032}
1033
1034static int wl1271_fetch_nvs(struct wl1271 *wl)
1035{
1036 const struct firmware *fw;
1037 int ret;
1038
Felipe Balbia390e852011-10-06 10:07:44 +03001039 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040
1041 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001042 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
1043 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001044 return ret;
1045 }
1046
Shahar Levibc765bf2011-03-06 16:32:10 +02001047 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048
1049 if (!wl->nvs) {
1050 wl1271_error("could not allocate memory for the nvs file");
1051 ret = -ENOMEM;
1052 goto out;
1053 }
1054
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001055 wl->nvs_len = fw->size;
1056
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057out:
1058 release_firmware(fw);
1059
1060 return ret;
1061}
1062
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001063void wl12xx_queue_recovery_work(struct wl1271 *wl)
1064{
1065 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1066 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1067}
1068
Ido Yariv95dac04f2011-06-06 14:57:06 +03001069size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1070{
1071 size_t len = 0;
1072
1073 /* The FW log is a length-value list, find where the log end */
1074 while (len < maxlen) {
1075 if (memblock[len] == 0)
1076 break;
1077 if (len + memblock[len] + 1 > maxlen)
1078 break;
1079 len += memblock[len] + 1;
1080 }
1081
1082 /* Make sure we have enough room */
1083 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1084
1085 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1086 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1087 wl->fwlog_size += len;
1088
1089 return len;
1090}
1091
1092static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1093{
1094 u32 addr;
1095 u32 first_addr;
1096 u8 *block;
1097
1098 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1099 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1100 (wl->conf.fwlog.mem_blocks == 0))
1101 return;
1102
1103 wl1271_info("Reading FW panic log");
1104
1105 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1106 if (!block)
1107 return;
1108
1109 /*
1110 * Make sure the chip is awake and the logger isn't active.
1111 * This might fail if the firmware hanged.
1112 */
1113 if (!wl1271_ps_elp_wakeup(wl))
1114 wl12xx_cmd_stop_fwlog(wl);
1115
1116 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001117 wl12xx_fw_status(wl, wl->fw_status);
1118 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001119 if (!first_addr)
1120 goto out;
1121
1122 /* Traverse the memory blocks linked list */
1123 addr = first_addr;
1124 do {
1125 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1126 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1127 false);
1128
1129 /*
1130 * Memory blocks are linked to one another. The first 4 bytes
1131 * of each memory block hold the hardware address of the next
1132 * one. The last memory block points to the first one.
1133 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001134 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001135 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1136 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1137 break;
1138 } while (addr && (addr != first_addr));
1139
1140 wake_up_interruptible(&wl->fwlog_waitq);
1141
1142out:
1143 kfree(block);
1144}
1145
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001146static void wl1271_recovery_work(struct work_struct *work)
1147{
1148 struct wl1271 *wl =
1149 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001150 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001151 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001152
1153 mutex_lock(&wl->mutex);
1154
1155 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001156 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001157
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001158 /* Avoid a recursive recovery */
1159 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1160
Ido Yariv95dac04f2011-06-06 14:57:06 +03001161 wl12xx_read_fwlog_panic(wl);
1162
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001163 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1164 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001165
Eliad Peller2a5bff02011-08-25 18:10:59 +03001166 BUG_ON(bug_on_recovery);
1167
Oz Krakowskib992c682011-06-26 10:36:02 +03001168 /*
1169 * Advance security sequence number to overcome potential progress
1170 * in the firmware during recovery. This doens't hurt if the network is
1171 * not encrypted.
1172 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001173 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001174 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001175 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001176 wlvif->tx_security_seq +=
1177 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1178 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001179
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001180 /* Prevent spurious TX during FW restart */
1181 ieee80211_stop_queues(wl->hw);
1182
Luciano Coelho33c2c062011-05-10 14:46:02 +03001183 if (wl->sched_scanning) {
1184 ieee80211_sched_scan_stopped(wl->hw);
1185 wl->sched_scanning = false;
1186 }
1187
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001188 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001189 while (!list_empty(&wl->wlvif_list)) {
1190 wlvif = list_first_entry(&wl->wlvif_list,
1191 struct wl12xx_vif, list);
1192 vif = wl12xx_wlvif_to_vif(wlvif);
1193 __wl1271_op_remove_interface(wl, vif, false);
1194 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001195 mutex_unlock(&wl->mutex);
1196 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001197
1198 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1199
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001200 ieee80211_restart_hw(wl->hw);
1201
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001202 /*
1203 * Its safe to enable TX now - the queues are stopped after a request
1204 * to restart the HW.
1205 */
1206 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001207 return;
1208out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001209 mutex_unlock(&wl->mutex);
1210}
1211
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001212static void wl1271_fw_wakeup(struct wl1271 *wl)
1213{
1214 u32 elp_reg;
1215
1216 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001217 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218}
1219
1220static int wl1271_setup(struct wl1271 *wl)
1221{
1222 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1223 if (!wl->fw_status)
1224 return -ENOMEM;
1225
1226 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1227 if (!wl->tx_res_if) {
1228 kfree(wl->fw_status);
1229 return -ENOMEM;
1230 }
1231
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001232 return 0;
1233}
1234
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001235static int wl12xx_set_power_on(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001236{
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001237 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001238
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001239 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001240 ret = wl1271_power_on(wl);
1241 if (ret < 0)
1242 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001243 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001244 wl1271_io_reset(wl);
1245 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001246
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001247 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001248
1249 /* ELP module wake up */
1250 wl1271_fw_wakeup(wl);
1251
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001252out:
1253 return ret;
1254}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001255
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001256static int wl1271_chip_wakeup(struct wl1271 *wl)
1257{
1258 int ret = 0;
1259
1260 ret = wl12xx_set_power_on(wl);
1261 if (ret < 0)
1262 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001263
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001264 /*
1265 * For wl127x based devices we could use the default block
1266 * size (512 bytes), but due to a bug in the sdio driver, we
1267 * need to set it explicitly after the chip is powered on. To
1268 * simplify the code and since the performance impact is
1269 * negligible, we use the same block size for all different
1270 * chip types.
1271 */
1272 if (!wl1271_set_block_size(wl))
1273 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001274
1275 switch (wl->chip.id) {
1276 case CHIP_ID_1271_PG10:
1277 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1278 wl->chip.id);
1279
1280 ret = wl1271_setup(wl);
1281 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001282 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001283 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001284 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001285
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001286 case CHIP_ID_1271_PG20:
1287 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1288 wl->chip.id);
1289
1290 ret = wl1271_setup(wl);
1291 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001292 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001293 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001295
Shahar Levi0830cee2011-03-06 16:32:20 +02001296 case CHIP_ID_1283_PG20:
1297 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1298 wl->chip.id);
1299
1300 ret = wl1271_setup(wl);
1301 if (ret < 0)
1302 goto out;
1303 break;
1304 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001305 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001306 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001307 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001308 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001309 }
1310
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001311 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001312 ret = wl1271_fetch_firmware(wl);
1313 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001314 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315 }
1316
1317 /* No NVS from netlink, try to get it from the filesystem */
1318 if (wl->nvs == NULL) {
1319 ret = wl1271_fetch_nvs(wl);
1320 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001321 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322 }
1323
1324out:
1325 return ret;
1326}
1327
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001328int wl1271_plt_start(struct wl1271 *wl)
1329{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001330 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001331 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001332 int ret;
1333
1334 mutex_lock(&wl->mutex);
1335
1336 wl1271_notice("power up");
1337
1338 if (wl->state != WL1271_STATE_OFF) {
1339 wl1271_error("cannot go into PLT state because not "
1340 "in off state: %d", wl->state);
1341 ret = -EBUSY;
1342 goto out;
1343 }
1344
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001345 while (retries) {
1346 retries--;
1347 ret = wl1271_chip_wakeup(wl);
1348 if (ret < 0)
1349 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001350
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001351 ret = wl1271_boot(wl);
1352 if (ret < 0)
1353 goto power_off;
1354
1355 ret = wl1271_plt_init(wl);
1356 if (ret < 0)
1357 goto irq_disable;
1358
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001359 wl->state = WL1271_STATE_PLT;
1360 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001361 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001362
Gery Kahn6f07b722011-07-18 14:21:49 +03001363 /* update hw/fw version info in wiphy struct */
1364 wiphy->hw_version = wl->chip.id;
1365 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1366 sizeof(wiphy->fw_version));
1367
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368 goto out;
1369
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001370irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001371 mutex_unlock(&wl->mutex);
1372 /* Unlocking the mutex in the middle of handling is
1373 inherently unsafe. In this case we deem it safe to do,
1374 because we need to let any possibly pending IRQ out of
1375 the system (and while we are WL1271_STATE_OFF the IRQ
1376 work function will not do anything.) Also, any other
1377 possible concurrent operations will fail due to the
1378 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001379 wl1271_disable_interrupts(wl);
1380 wl1271_flush_deferred_work(wl);
1381 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001382 mutex_lock(&wl->mutex);
1383power_off:
1384 wl1271_power_off(wl);
1385 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001386
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001387 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1388 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001389out:
1390 mutex_unlock(&wl->mutex);
1391
1392 return ret;
1393}
1394
Ido Yarivf3df1332012-01-11 09:42:39 +02001395int wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001396{
1397 int ret = 0;
1398
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001399 wl1271_notice("power down");
1400
Ido Yariv46b0cc92012-01-11 09:42:41 +02001401 /*
1402 * Interrupts must be disabled before setting the state to OFF.
1403 * Otherwise, the interrupt handler might be called and exit without
1404 * reading the interrupt status.
1405 */
1406 wl1271_disable_interrupts(wl);
Ido Yarivf3df1332012-01-11 09:42:39 +02001407 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001408 if (wl->state != WL1271_STATE_PLT) {
Ido Yarivf3df1332012-01-11 09:42:39 +02001409 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001410
1411 /*
1412 * This will not necessarily enable interrupts as interrupts
1413 * may have been disabled when op_stop was called. It will,
1414 * however, balance the above call to disable_interrupts().
1415 */
1416 wl1271_enable_interrupts(wl);
1417
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001418 wl1271_error("cannot power down because not in PLT "
1419 "state: %d", wl->state);
1420 ret = -EBUSY;
1421 goto out;
1422 }
1423
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001424 mutex_unlock(&wl->mutex);
Ido Yarivf3df1332012-01-11 09:42:39 +02001425
Ido Yariva6208652011-03-01 15:14:41 +02001426 wl1271_flush_deferred_work(wl);
1427 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001428 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001429 cancel_delayed_work_sync(&wl->elp_work);
Ido Yariva4549692012-01-11 09:42:40 +02001430
1431 mutex_lock(&wl->mutex);
1432 wl1271_power_off(wl);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001433 wl->flags = 0;
1434 wl->state = WL1271_STATE_OFF;
1435 wl->rx_counter = 0;
Ido Yariva4549692012-01-11 09:42:40 +02001436 mutex_unlock(&wl->mutex);
1437
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001438out:
1439 return ret;
1440}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001441
Johannes Berg7bb45682011-02-24 14:42:06 +01001442static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001443{
1444 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001445 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1446 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001447 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001448 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001449 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001450 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001451
Eliad Peller0f168012011-10-11 13:52:25 +02001452 if (vif)
1453 wlvif = wl12xx_vif_to_data(vif);
1454
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001455 mapping = skb_get_queue_mapping(skb);
1456 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001457
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001458 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001459
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001460 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001461
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001462 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001463 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001464 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001465 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001466 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001467 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001468 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001469
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001470 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1471 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1472
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001473 wl->tx_queue_count[q]++;
1474
1475 /*
1476 * The workqueue is slow to process the tx_queue and we need stop
1477 * the queue here, otherwise the queue will get too long.
1478 */
1479 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1480 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1481 ieee80211_stop_queue(wl->hw, mapping);
1482 set_bit(q, &wl->stopped_queues_map);
1483 }
1484
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001485 /*
1486 * The chip specific setup must run before the first TX packet -
1487 * before that, the tx_work will not be initialized!
1488 */
1489
Ido Yarivb07d4032011-03-01 15:14:43 +02001490 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1491 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001492 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001493
Arik Nemtsov04216da2011-08-14 13:17:38 +03001494out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001495 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001496}
1497
Shahar Leviae47c452011-03-06 16:32:14 +02001498int wl1271_tx_dummy_packet(struct wl1271 *wl)
1499{
Ido Yariv990f5de2011-03-31 10:06:59 +02001500 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001501 int q;
1502
1503 /* no need to queue a new dummy packet if one is already pending */
1504 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1505 return 0;
1506
1507 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001508
Ido Yariv990f5de2011-03-31 10:06:59 +02001509 spin_lock_irqsave(&wl->wl_lock, flags);
1510 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001511 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001512 spin_unlock_irqrestore(&wl->wl_lock, flags);
1513
1514 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1515 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001516 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001517
1518 /*
1519 * If the FW TX is busy, TX work will be scheduled by the threaded
1520 * interrupt handler function
1521 */
1522 return 0;
1523}
1524
1525/*
1526 * The size of the dummy packet should be at least 1400 bytes. However, in
1527 * order to minimize the number of bus transactions, aligning it to 512 bytes
1528 * boundaries could be beneficial, performance wise
1529 */
1530#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1531
Luciano Coelhocf27d862011-04-01 21:08:23 +03001532static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001533{
1534 struct sk_buff *skb;
1535 struct ieee80211_hdr_3addr *hdr;
1536 unsigned int dummy_packet_size;
1537
1538 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1539 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1540
1541 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001542 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001543 wl1271_warning("Failed to allocate a dummy packet skb");
1544 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001545 }
1546
1547 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1548
1549 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1550 memset(hdr, 0, sizeof(*hdr));
1551 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001552 IEEE80211_STYPE_NULLFUNC |
1553 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001554
Ido Yariv990f5de2011-03-31 10:06:59 +02001555 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001556
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001557 /* Dummy packets require the TID to be management */
1558 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001559
1560 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001561 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001562 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001563
Ido Yariv990f5de2011-03-31 10:06:59 +02001564 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001565}
1566
Ido Yariv990f5de2011-03-31 10:06:59 +02001567
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001568static struct notifier_block wl1271_dev_notifier = {
1569 .notifier_call = wl1271_dev_notify,
1570};
1571
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001572#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001573static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1574 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001575{
Eliad Pellere85d1622011-06-27 13:06:43 +03001576 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001577
Eliad Peller94390642011-05-13 11:57:13 +03001578 mutex_lock(&wl->mutex);
1579
Eliad Pellerba8447f2011-10-10 10:13:00 +02001580 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001581 goto out_unlock;
1582
Eliad Peller94390642011-05-13 11:57:13 +03001583 ret = wl1271_ps_elp_wakeup(wl);
1584 if (ret < 0)
1585 goto out_unlock;
1586
1587 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001588 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001589 DECLARE_COMPLETION_ONSTACK(compl);
1590
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001591 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001592 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001593 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001594 if (ret < 0)
1595 goto out_sleep;
1596
1597 /* we must unlock here so we will be able to get events */
1598 wl1271_ps_elp_sleep(wl);
1599 mutex_unlock(&wl->mutex);
1600
1601 ret = wait_for_completion_timeout(
1602 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
Pontus Fuchsef187062011-12-14 14:32:23 +01001603
1604 mutex_lock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001605 if (ret <= 0) {
1606 wl1271_warning("couldn't enter ps mode!");
1607 ret = -EBUSY;
Pontus Fuchsef187062011-12-14 14:32:23 +01001608 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001609 }
1610
Eliad Peller94390642011-05-13 11:57:13 +03001611 ret = wl1271_ps_elp_wakeup(wl);
1612 if (ret < 0)
Pontus Fuchsef187062011-12-14 14:32:23 +01001613 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001614 }
1615out_sleep:
1616 wl1271_ps_elp_sleep(wl);
Pontus Fuchsef187062011-12-14 14:32:23 +01001617out_cleanup:
1618 wlvif->ps_compl = NULL;
Eliad Peller94390642011-05-13 11:57:13 +03001619out_unlock:
1620 mutex_unlock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001621 return ret;
1622
1623}
1624
Eliad Peller0603d892011-10-05 11:55:51 +02001625static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1626 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001627{
Eliad Pellere85d1622011-06-27 13:06:43 +03001628 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001629
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001630 mutex_lock(&wl->mutex);
1631
Eliad Peller53d40d02011-10-10 10:13:02 +02001632 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001633 goto out_unlock;
1634
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001635 ret = wl1271_ps_elp_wakeup(wl);
1636 if (ret < 0)
1637 goto out_unlock;
1638
Eliad Peller0603d892011-10-05 11:55:51 +02001639 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001640
1641 wl1271_ps_elp_sleep(wl);
1642out_unlock:
1643 mutex_unlock(&wl->mutex);
1644 return ret;
1645
1646}
1647
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001648static int wl1271_configure_suspend(struct wl1271 *wl,
1649 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001650{
Eliad Peller536129c2011-10-05 11:55:45 +02001651 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001652 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001653 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001654 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001655 return 0;
1656}
1657
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001658static void wl1271_configure_resume(struct wl1271 *wl,
1659 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001660{
1661 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001662 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1663 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001664
1665 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001666 return;
1667
1668 mutex_lock(&wl->mutex);
1669 ret = wl1271_ps_elp_wakeup(wl);
1670 if (ret < 0)
1671 goto out;
1672
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001673 if (is_sta) {
1674 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001675 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001676 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001677 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001678 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001679 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001680 }
Eliad Peller94390642011-05-13 11:57:13 +03001681
1682 wl1271_ps_elp_sleep(wl);
1683out:
1684 mutex_unlock(&wl->mutex);
1685}
1686
Eliad Peller402e48612011-05-13 11:57:09 +03001687static int wl1271_op_suspend(struct ieee80211_hw *hw,
1688 struct cfg80211_wowlan *wow)
1689{
1690 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001691 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001692 int ret;
1693
Eliad Peller402e48612011-05-13 11:57:09 +03001694 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001695 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001696
Eliad Peller4a859df2011-06-06 12:21:52 +03001697 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001698 wl12xx_for_each_wlvif(wl, wlvif) {
1699 ret = wl1271_configure_suspend(wl, wlvif);
1700 if (ret < 0) {
1701 wl1271_warning("couldn't prepare device to suspend");
1702 return ret;
1703 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001704 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001705 /* flush any remaining work */
1706 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001707
1708 /*
1709 * disable and re-enable interrupts in order to flush
1710 * the threaded_irq
1711 */
1712 wl1271_disable_interrupts(wl);
1713
1714 /*
1715 * set suspended flag to avoid triggering a new threaded_irq
1716 * work. no need for spinlock as interrupts are disabled.
1717 */
1718 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1719
1720 wl1271_enable_interrupts(wl);
1721 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001722 wl12xx_for_each_wlvif(wl, wlvif) {
1723 flush_delayed_work(&wlvif->pspoll_work);
1724 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001725 flush_delayed_work(&wl->elp_work);
1726
Eliad Peller402e48612011-05-13 11:57:09 +03001727 return 0;
1728}
1729
1730static int wl1271_op_resume(struct ieee80211_hw *hw)
1731{
1732 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001733 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001734 unsigned long flags;
1735 bool run_irq_work = false;
1736
Eliad Peller402e48612011-05-13 11:57:09 +03001737 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1738 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001739 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001740
1741 /*
1742 * re-enable irq_work enqueuing, and call irq_work directly if
1743 * there is a pending work.
1744 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001745 spin_lock_irqsave(&wl->wl_lock, flags);
1746 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1747 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1748 run_irq_work = true;
1749 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001750
Eliad Peller4a859df2011-06-06 12:21:52 +03001751 if (run_irq_work) {
1752 wl1271_debug(DEBUG_MAC80211,
1753 "run postponed irq_work directly");
1754 wl1271_irq(0, wl);
1755 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001756 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001757 wl12xx_for_each_wlvif(wl, wlvif) {
1758 wl1271_configure_resume(wl, wlvif);
1759 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001760 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001761
Eliad Peller402e48612011-05-13 11:57:09 +03001762 return 0;
1763}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001764#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001765
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001766static int wl1271_op_start(struct ieee80211_hw *hw)
1767{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001768 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1769
1770 /*
1771 * We have to delay the booting of the hardware because
1772 * we need to know the local MAC address before downloading and
1773 * initializing the firmware. The MAC address cannot be changed
1774 * after boot, and without the proper MAC address, the firmware
1775 * will not function properly.
1776 *
1777 * The MAC address is first known when the corresponding interface
1778 * is added. That is where we will initialize the hardware.
1779 */
1780
1781 return 0;
1782}
1783
1784static void wl1271_op_stop(struct ieee80211_hw *hw)
1785{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001786 struct wl1271 *wl = hw->priv;
1787 int i;
1788
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001789 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001790
Ido Yariv46b0cc92012-01-11 09:42:41 +02001791 /*
1792 * Interrupts must be disabled before setting the state to OFF.
1793 * Otherwise, the interrupt handler might be called and exit without
1794 * reading the interrupt status.
1795 */
1796 wl1271_disable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001797 mutex_lock(&wl->mutex);
1798 if (wl->state == WL1271_STATE_OFF) {
1799 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001800
1801 /*
1802 * This will not necessarily enable interrupts as interrupts
1803 * may have been disabled when op_stop was called. It will,
1804 * however, balance the above call to disable_interrupts().
1805 */
1806 wl1271_enable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001807 return;
1808 }
Ido Yariv46b0cc92012-01-11 09:42:41 +02001809
Eliad Pellerbaf62772011-10-10 10:12:52 +02001810 /*
1811 * this must be before the cancel_work calls below, so that the work
1812 * functions don't perform further work.
1813 */
1814 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001815 mutex_unlock(&wl->mutex);
1816
1817 mutex_lock(&wl_list_mutex);
1818 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001819 mutex_unlock(&wl_list_mutex);
1820
Eliad Pellerbaf62772011-10-10 10:12:52 +02001821 wl1271_flush_deferred_work(wl);
1822 cancel_delayed_work_sync(&wl->scan_complete_work);
1823 cancel_work_sync(&wl->netstack_work);
1824 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001825 cancel_delayed_work_sync(&wl->elp_work);
1826
1827 /* let's notify MAC80211 about the remaining pending TX frames */
1828 wl12xx_tx_reset(wl, true);
1829 mutex_lock(&wl->mutex);
1830
1831 wl1271_power_off(wl);
1832
1833 wl->band = IEEE80211_BAND_2GHZ;
1834
1835 wl->rx_counter = 0;
1836 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1837 wl->tx_blocks_available = 0;
1838 wl->tx_allocated_blocks = 0;
1839 wl->tx_results_count = 0;
1840 wl->tx_packets_count = 0;
1841 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001842 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1843 wl->ap_fw_ps_map = 0;
1844 wl->ap_ps_map = 0;
1845 wl->sched_scanning = false;
1846 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1847 memset(wl->links_map, 0, sizeof(wl->links_map));
1848 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1849 wl->active_sta_count = 0;
1850
1851 /* The system link is always allocated */
1852 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1853
1854 /*
1855 * this is performed after the cancel_work calls and the associated
1856 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1857 * get executed before all these vars have been reset.
1858 */
1859 wl->flags = 0;
1860
1861 wl->tx_blocks_freed = 0;
1862
1863 for (i = 0; i < NUM_TX_QUEUES; i++) {
1864 wl->tx_pkts_freed[i] = 0;
1865 wl->tx_allocated_pkts[i] = 0;
1866 }
1867
1868 wl1271_debugfs_reset(wl);
1869
1870 kfree(wl->fw_status);
1871 wl->fw_status = NULL;
1872 kfree(wl->tx_res_if);
1873 wl->tx_res_if = NULL;
1874 kfree(wl->target_mem_map);
1875 wl->target_mem_map = NULL;
1876
1877 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001878}
1879
Eliad Pellere5a359f2011-10-10 10:13:15 +02001880static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1881{
1882 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1883 WL12XX_MAX_RATE_POLICIES);
1884 if (policy >= WL12XX_MAX_RATE_POLICIES)
1885 return -EBUSY;
1886
1887 __set_bit(policy, wl->rate_policies_map);
1888 *idx = policy;
1889 return 0;
1890}
1891
1892static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1893{
1894 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1895 return;
1896
1897 __clear_bit(*idx, wl->rate_policies_map);
1898 *idx = WL12XX_MAX_RATE_POLICIES;
1899}
1900
Eliad Peller536129c2011-10-05 11:55:45 +02001901static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001902{
Eliad Peller536129c2011-10-05 11:55:45 +02001903 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001904 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001905 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001906 return WL1271_ROLE_P2P_GO;
1907 else
1908 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001909
1910 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001911 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001912 return WL1271_ROLE_P2P_CL;
1913 else
1914 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001915
Eliad Peller227e81e2011-08-14 13:17:26 +03001916 case BSS_TYPE_IBSS:
1917 return WL1271_ROLE_IBSS;
1918
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001919 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001920 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001921 }
1922 return WL12XX_INVALID_ROLE_TYPE;
1923}
1924
Eliad Peller83587502011-10-10 10:12:53 +02001925static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001926{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001927 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001928 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001929
Eliad Peller48e93e42011-10-10 10:12:58 +02001930 /* clear everything but the persistent data */
1931 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001932
1933 switch (ieee80211_vif_type_p2p(vif)) {
1934 case NL80211_IFTYPE_P2P_CLIENT:
1935 wlvif->p2p = 1;
1936 /* fall-through */
1937 case NL80211_IFTYPE_STATION:
1938 wlvif->bss_type = BSS_TYPE_STA_BSS;
1939 break;
1940 case NL80211_IFTYPE_ADHOC:
1941 wlvif->bss_type = BSS_TYPE_IBSS;
1942 break;
1943 case NL80211_IFTYPE_P2P_GO:
1944 wlvif->p2p = 1;
1945 /* fall-through */
1946 case NL80211_IFTYPE_AP:
1947 wlvif->bss_type = BSS_TYPE_AP_BSS;
1948 break;
1949 default:
1950 wlvif->bss_type = MAX_BSS_TYPE;
1951 return -EOPNOTSUPP;
1952 }
1953
Eliad Peller0603d892011-10-05 11:55:51 +02001954 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001955 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001956 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001957
Eliad Pellere936bbe2011-10-05 11:55:56 +02001958 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1959 wlvif->bss_type == BSS_TYPE_IBSS) {
1960 /* init sta/ibss data */
1961 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001962 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1963 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1964 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001965 } else {
1966 /* init ap data */
1967 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1968 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001969 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1970 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1971 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1972 wl12xx_allocate_rate_policy(wl,
1973 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001974 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001975
Eliad Peller83587502011-10-10 10:12:53 +02001976 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1977 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001978 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001979 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001980 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001981 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1982
Eliad Peller1b92f152011-10-10 10:13:09 +02001983 /*
1984 * mac80211 configures some values globally, while we treat them
1985 * per-interface. thus, on init, we have to copy them from wl
1986 */
1987 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001988 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001989 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02001990
Eliad Peller9eb599e2011-10-10 10:12:59 +02001991 INIT_WORK(&wlvif->rx_streaming_enable_work,
1992 wl1271_rx_streaming_enable_work);
1993 INIT_WORK(&wlvif->rx_streaming_disable_work,
1994 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02001995 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02001996 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001997
Eliad Peller9eb599e2011-10-10 10:12:59 +02001998 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1999 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002000 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002001}
2002
Eliad Peller1d095472011-10-10 10:12:49 +02002003static bool wl12xx_init_fw(struct wl1271 *wl)
2004{
2005 int retries = WL1271_BOOT_RETRIES;
2006 bool booted = false;
2007 struct wiphy *wiphy = wl->hw->wiphy;
2008 int ret;
2009
2010 while (retries) {
2011 retries--;
2012 ret = wl1271_chip_wakeup(wl);
2013 if (ret < 0)
2014 goto power_off;
2015
2016 ret = wl1271_boot(wl);
2017 if (ret < 0)
2018 goto power_off;
2019
2020 ret = wl1271_hw_init(wl);
2021 if (ret < 0)
2022 goto irq_disable;
2023
2024 booted = true;
2025 break;
2026
2027irq_disable:
2028 mutex_unlock(&wl->mutex);
2029 /* Unlocking the mutex in the middle of handling is
2030 inherently unsafe. In this case we deem it safe to do,
2031 because we need to let any possibly pending IRQ out of
2032 the system (and while we are WL1271_STATE_OFF the IRQ
2033 work function will not do anything.) Also, any other
2034 possible concurrent operations will fail due to the
2035 current state, hence the wl1271 struct should be safe. */
2036 wl1271_disable_interrupts(wl);
2037 wl1271_flush_deferred_work(wl);
2038 cancel_work_sync(&wl->netstack_work);
2039 mutex_lock(&wl->mutex);
2040power_off:
2041 wl1271_power_off(wl);
2042 }
2043
2044 if (!booted) {
2045 wl1271_error("firmware boot failed despite %d retries",
2046 WL1271_BOOT_RETRIES);
2047 goto out;
2048 }
2049
2050 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2051
2052 /* update hw/fw version info in wiphy struct */
2053 wiphy->hw_version = wl->chip.id;
2054 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2055 sizeof(wiphy->fw_version));
2056
2057 /*
2058 * Now we know if 11a is supported (info from the NVS), so disable
2059 * 11a channels if not supported
2060 */
2061 if (!wl->enable_11a)
2062 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2063
2064 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2065 wl->enable_11a ? "" : "not ");
2066
2067 wl->state = WL1271_STATE_ON;
2068out:
2069 return booted;
2070}
2071
Eliad Peller92e712d2011-12-18 20:25:43 +02002072static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2073{
2074 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2075}
2076
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002077static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2078 struct ieee80211_vif *vif)
2079{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002080 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002081 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002082 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002083 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002084 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002085
Johannes Bergea086352012-01-19 09:29:58 +01002086 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2087 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002088
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002089 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002090 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002091
2092 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002093 ret = wl1271_ps_elp_wakeup(wl);
2094 if (ret < 0)
2095 goto out_unlock;
2096
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002097 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002098 wl1271_debug(DEBUG_MAC80211,
2099 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002100 ret = -EBUSY;
2101 goto out;
2102 }
2103
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002104 /*
2105 * in some very corner case HW recovery scenarios its possible to
2106 * get here before __wl1271_op_remove_interface is complete, so
2107 * opt out if that is the case.
2108 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002109 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2110 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002111 ret = -EBUSY;
2112 goto out;
2113 }
2114
Eliad Peller83587502011-10-10 10:12:53 +02002115 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002116 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002117 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002118
Eliad Peller252efa42011-10-05 11:56:00 +02002119 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002120 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002121 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2122 ret = -EINVAL;
2123 goto out;
2124 }
Eliad Peller1d095472011-10-10 10:12:49 +02002125
Eliad Peller784f6942011-10-05 11:55:39 +02002126 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002127 * TODO: after the nvs issue will be solved, move this block
2128 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002129 */
Eliad Peller1d095472011-10-10 10:12:49 +02002130 if (wl->state == WL1271_STATE_OFF) {
2131 /*
2132 * we still need this in order to configure the fw
2133 * while uploading the nvs
2134 */
Luciano Coelho5e037e72011-12-23 09:32:17 +02002135 memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002136
Eliad Peller1d095472011-10-10 10:12:49 +02002137 booted = wl12xx_init_fw(wl);
2138 if (!booted) {
2139 ret = -EINVAL;
2140 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002141 }
Eliad Peller1d095472011-10-10 10:12:49 +02002142 }
Eliad Peller04e80792011-08-14 13:17:09 +03002143
Eliad Peller1d095472011-10-10 10:12:49 +02002144 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2145 wlvif->bss_type == BSS_TYPE_IBSS) {
2146 /*
2147 * The device role is a special role used for
2148 * rx and tx frames prior to association (as
2149 * the STA role can get packets only from
2150 * its associated bssid)
2151 */
Eliad Peller784f6942011-10-05 11:55:39 +02002152 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002153 WL1271_ROLE_DEVICE,
2154 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002155 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002156 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002157 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002158
Eliad Peller1d095472011-10-10 10:12:49 +02002159 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2160 role_type, &wlvif->role_id);
2161 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002162 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002163
2164 ret = wl1271_init_vif_specific(wl, vif);
2165 if (ret < 0)
2166 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002167
2168 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002169 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002170 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002171
2172 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2173 wl->ap_count++;
2174 else
2175 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002176out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002177 wl1271_ps_elp_sleep(wl);
2178out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002179 mutex_unlock(&wl->mutex);
2180
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002181 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002182 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002183 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002184 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002185
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002186 return ret;
2187}
2188
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002189static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002190 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002191 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002192{
Eliad Peller536129c2011-10-05 11:55:45 +02002193 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002194 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002195
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002196 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002197
Eliad Peller10c8cd02011-10-10 10:13:06 +02002198 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2199 return;
2200
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002201 wl->vif = NULL;
2202
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002203 /* because of hardware recovery, we may get here twice */
2204 if (wl->state != WL1271_STATE_ON)
2205 return;
2206
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002207 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002208
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002209 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002210 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002211 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002212
Eliad Pellerbaf62772011-10-10 10:12:52 +02002213 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2214 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002215 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002216 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002217 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002218 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002219 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002220 }
2221
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002222 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2223 /* disable active roles */
2224 ret = wl1271_ps_elp_wakeup(wl);
2225 if (ret < 0)
2226 goto deinit;
2227
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002228 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2229 wlvif->bss_type == BSS_TYPE_IBSS) {
2230 if (wl12xx_dev_role_started(wlvif))
2231 wl12xx_stop_dev(wl, wlvif);
2232
Eliad Peller7edebf52011-10-05 11:55:52 +02002233 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002234 if (ret < 0)
2235 goto deinit;
2236 }
2237
Eliad Peller0603d892011-10-05 11:55:51 +02002238 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002239 if (ret < 0)
2240 goto deinit;
2241
2242 wl1271_ps_elp_sleep(wl);
2243 }
2244deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002245 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002246 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002247
2248 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2249 wlvif->bss_type == BSS_TYPE_IBSS) {
2250 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2251 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2252 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2253 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2254 } else {
2255 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2256 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2257 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2258 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2259 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2260 wl12xx_free_rate_policy(wl,
2261 &wlvif->ap.ucast_rate_idx[i]);
2262 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002263
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002264 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002265 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002266 if (wl->last_wlvif == wlvif)
2267 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002268 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002269 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002270 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002271 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002272
Eliad Pellera4e41302011-10-11 11:49:15 +02002273 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2274 wl->ap_count--;
2275 else
2276 wl->sta_count--;
2277
Eliad Pellerbaf62772011-10-10 10:12:52 +02002278 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002279 del_timer_sync(&wlvif->rx_streaming_timer);
2280 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2281 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002282 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002283
Eliad Pellerbaf62772011-10-10 10:12:52 +02002284 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002285}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002286
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002287static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2288 struct ieee80211_vif *vif)
2289{
2290 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002291 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002292 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002293
2294 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002295
2296 if (wl->state == WL1271_STATE_OFF ||
2297 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2298 goto out;
2299
Juuso Oikarinen67353292010-11-18 15:19:02 +02002300 /*
2301 * wl->vif can be null here if someone shuts down the interface
2302 * just when hardware recovery has been started.
2303 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002304 wl12xx_for_each_wlvif(wl, iter) {
2305 if (iter != wlvif)
2306 continue;
2307
Eliad Peller536129c2011-10-05 11:55:45 +02002308 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002309 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002310 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002311 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002312out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002313 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002314 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002315}
2316
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002317static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2318 struct ieee80211_vif *vif,
2319 enum nl80211_iftype new_type, bool p2p)
2320{
2321 wl1271_op_remove_interface(hw, vif);
2322
2323 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2324 vif->p2p = p2p;
2325 return wl1271_op_add_interface(hw, vif);
2326}
2327
Eliad Peller87fbcb02011-10-05 11:55:41 +02002328static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2329 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002330{
2331 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002332 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002333
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002334 /*
2335 * One of the side effects of the JOIN command is that is clears
2336 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2337 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002338 * Currently the only valid scenario for JOIN during association
2339 * is on roaming, in which case we will also be given new keys.
2340 * Keep the below message for now, unless it starts bothering
2341 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002342 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002343 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002344 wl1271_info("JOIN while associated.");
2345
2346 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002347 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002348
Eliad Peller227e81e2011-08-14 13:17:26 +03002349 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002350 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002351 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002352 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002353 if (ret < 0)
2354 goto out;
2355
Eliad Pellerba8447f2011-10-10 10:13:00 +02002356 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002357 goto out;
2358
2359 /*
2360 * The join command disable the keep-alive mode, shut down its process,
2361 * and also clear the template config, so we need to reset it all after
2362 * the join. The acx_aid starts the keep-alive process, and the order
2363 * of the commands below is relevant.
2364 */
Eliad Peller0603d892011-10-05 11:55:51 +02002365 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002366 if (ret < 0)
2367 goto out;
2368
Eliad Peller0603d892011-10-05 11:55:51 +02002369 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002370 if (ret < 0)
2371 goto out;
2372
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002373 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002374 if (ret < 0)
2375 goto out;
2376
Eliad Peller0603d892011-10-05 11:55:51 +02002377 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2378 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002379 ACX_KEEP_ALIVE_TPL_VALID);
2380 if (ret < 0)
2381 goto out;
2382
2383out:
2384 return ret;
2385}
2386
Eliad Peller0603d892011-10-05 11:55:51 +02002387static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002388{
2389 int ret;
2390
Eliad Peller52630c52011-10-10 10:13:08 +02002391 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002392 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2393
Shahar Levi6d158ff2011-09-08 13:01:33 +03002394 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002395 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002396 }
2397
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002398 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002399 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002400 if (ret < 0)
2401 goto out;
2402
Oz Krakowskib992c682011-06-26 10:36:02 +03002403 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002404 wlvif->tx_security_last_seq_lsb = 0;
2405 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002406
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002407out:
2408 return ret;
2409}
2410
Eliad Peller87fbcb02011-10-05 11:55:41 +02002411static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002412{
Eliad Peller1b92f152011-10-10 10:13:09 +02002413 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002414 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002415}
2416
Eliad Peller87fbcb02011-10-05 11:55:41 +02002417static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2418 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002419{
2420 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002421 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2422
2423 if (idle == cur_idle)
2424 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002425
2426 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002427 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002428 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002429 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002430 if (ret < 0)
2431 goto out;
2432 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002433 wlvif->rate_set =
2434 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2435 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002436 if (ret < 0)
2437 goto out;
2438 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002439 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002440 ACX_KEEP_ALIVE_TPL_INVALID);
2441 if (ret < 0)
2442 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002443 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002444 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002445 /* The current firmware only supports sched_scan in idle */
2446 if (wl->sched_scanning) {
2447 wl1271_scan_sched_scan_stop(wl);
2448 ieee80211_sched_scan_stopped(wl->hw);
2449 }
2450
Eliad Peller679a6732011-10-11 11:55:44 +02002451 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002452 if (ret < 0)
2453 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002454 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002455 }
2456
2457out:
2458 return ret;
2459}
2460
Eliad Peller9f259c42011-10-10 10:13:12 +02002461static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2462 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002463{
Eliad Peller9f259c42011-10-10 10:13:12 +02002464 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2465 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002466
2467 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2468
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002469 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002470 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002471 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002472 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002473 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002474 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002475 wlvif->band = conf->channel->band;
2476 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002477
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002478 if (!is_ap) {
2479 /*
2480 * FIXME: the mac80211 should really provide a fixed
2481 * rate to use here. for now, just use the smallest
2482 * possible rate for the band as a fixed rate for
2483 * association frames and other control messages.
2484 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002485 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002486 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002487
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002488 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002489 wl1271_tx_min_rate_get(wl,
2490 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002491 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002492 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002493 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002494 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002495
Eliad Pellerba8447f2011-10-10 10:13:00 +02002496 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2497 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002498 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002499 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002500 ret = wl12xx_croc(wl,
2501 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002502 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002503 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002504 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002505 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002506 if (ret < 0)
2507 wl1271_warning("cmd join on channel "
2508 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002509 } else {
2510 /*
2511 * change the ROC channel. do it only if we are
2512 * not idle. otherwise, CROC will be called
2513 * anyway.
2514 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002515 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002516 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002517 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002518 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002519 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002520
Eliad Peller679a6732011-10-11 11:55:44 +02002521 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002522 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002523 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002524 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002525 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002526 }
2527 }
2528
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002529 /*
2530 * if mac80211 changes the PSM mode, make sure the mode is not
2531 * incorrectly changed after the pspoll failure active window.
2532 */
2533 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002534 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002535
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002536 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002537 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2538 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002539
2540 /*
2541 * We enter PSM only if we're already associated.
2542 * If we're not, we'll enter it when joining an SSID,
2543 * through the bss_info_changed() hook.
2544 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002545 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002546 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002547 ret = wl1271_ps_set_mode(wl, wlvif,
2548 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002549 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002550 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002551 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002552 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002553 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002554
Eliad Pellerc29bb002011-10-10 10:13:03 +02002555 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002556
Eliad Pellerc29bb002011-10-10 10:13:03 +02002557 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002558 ret = wl1271_ps_set_mode(wl, wlvif,
2559 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002560 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002561 }
2562
Eliad Peller6bd65022011-10-10 10:13:11 +02002563 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002564 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002565 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002566 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002567
Eliad Peller6bd65022011-10-10 10:13:11 +02002568 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002569 }
2570
Eliad Peller9f259c42011-10-10 10:13:12 +02002571 return 0;
2572}
2573
2574static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2575{
2576 struct wl1271 *wl = hw->priv;
2577 struct wl12xx_vif *wlvif;
2578 struct ieee80211_conf *conf = &hw->conf;
2579 int channel, ret = 0;
2580
2581 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2582
2583 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2584 " changed 0x%x",
2585 channel,
2586 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2587 conf->power_level,
2588 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2589 changed);
2590
2591 /*
2592 * mac80211 will go to idle nearly immediately after transmitting some
2593 * frames, such as the deauth. To make sure those frames reach the air,
2594 * wait here until the TX queue is fully flushed.
2595 */
2596 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2597 (conf->flags & IEEE80211_CONF_IDLE))
2598 wl1271_tx_flush(wl);
2599
2600 mutex_lock(&wl->mutex);
2601
2602 /* we support configuring the channel and band even while off */
2603 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2604 wl->band = conf->channel->band;
2605 wl->channel = channel;
2606 }
2607
2608 if (changed & IEEE80211_CONF_CHANGE_POWER)
2609 wl->power_level = conf->power_level;
2610
2611 if (unlikely(wl->state == WL1271_STATE_OFF))
2612 goto out;
2613
2614 ret = wl1271_ps_elp_wakeup(wl);
2615 if (ret < 0)
2616 goto out;
2617
2618 /* configure each interface */
2619 wl12xx_for_each_wlvif(wl, wlvif) {
2620 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2621 if (ret < 0)
2622 goto out_sleep;
2623 }
2624
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002625out_sleep:
2626 wl1271_ps_elp_sleep(wl);
2627
2628out:
2629 mutex_unlock(&wl->mutex);
2630
2631 return ret;
2632}
2633
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002634struct wl1271_filter_params {
2635 bool enabled;
2636 int mc_list_length;
2637 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2638};
2639
Jiri Pirko22bedad2010-04-01 21:22:57 +00002640static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2641 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002642{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002643 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002644 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002645 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002646
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002647 if (unlikely(wl->state == WL1271_STATE_OFF))
2648 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002649
Juuso Oikarinen74441132009-10-13 12:47:53 +03002650 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002651 if (!fp) {
2652 wl1271_error("Out of memory setting filters.");
2653 return 0;
2654 }
2655
2656 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002657 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002658 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2659 fp->enabled = false;
2660 } else {
2661 fp->enabled = true;
2662 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002663 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002664 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002665 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002666 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002667 }
2668
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002669 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002670}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002671
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002672#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2673 FIF_ALLMULTI | \
2674 FIF_FCSFAIL | \
2675 FIF_BCN_PRBRESP_PROMISC | \
2676 FIF_CONTROL | \
2677 FIF_OTHER_BSS)
2678
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002679static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2680 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002681 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002682{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002683 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002684 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002685 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002686
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002687 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002688
Arik Nemtsov7d057862010-10-16 19:25:35 +02002689 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2690 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002691
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002692 mutex_lock(&wl->mutex);
2693
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002694 *total &= WL1271_SUPPORTED_FILTERS;
2695 changed &= WL1271_SUPPORTED_FILTERS;
2696
2697 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002698 goto out;
2699
Ido Yariva6208652011-03-01 15:14:41 +02002700 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002701 if (ret < 0)
2702 goto out;
2703
Eliad Peller6e8cd332011-10-10 10:13:13 +02002704 wl12xx_for_each_wlvif(wl, wlvif) {
2705 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2706 if (*total & FIF_ALLMULTI)
2707 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2708 false,
2709 NULL, 0);
2710 else if (fp)
2711 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2712 fp->enabled,
2713 fp->mc_list,
2714 fp->mc_list_length);
2715 if (ret < 0)
2716 goto out_sleep;
2717 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002718 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002719
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002720 /*
2721 * the fw doesn't provide an api to configure the filters. instead,
2722 * the filters configuration is based on the active roles / ROC
2723 * state.
2724 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002725
2726out_sleep:
2727 wl1271_ps_elp_sleep(wl);
2728
2729out:
2730 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002731 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002732}
2733
Eliad Peller170d0e62011-10-05 11:56:06 +02002734static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2735 u8 id, u8 key_type, u8 key_size,
2736 const u8 *key, u8 hlid, u32 tx_seq_32,
2737 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002738{
2739 struct wl1271_ap_key *ap_key;
2740 int i;
2741
2742 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2743
2744 if (key_size > MAX_KEY_SIZE)
2745 return -EINVAL;
2746
2747 /*
2748 * Find next free entry in ap_keys. Also check we are not replacing
2749 * an existing key.
2750 */
2751 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002752 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002753 break;
2754
Eliad Peller170d0e62011-10-05 11:56:06 +02002755 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002756 wl1271_warning("trying to record key replacement");
2757 return -EINVAL;
2758 }
2759 }
2760
2761 if (i == MAX_NUM_KEYS)
2762 return -EBUSY;
2763
2764 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2765 if (!ap_key)
2766 return -ENOMEM;
2767
2768 ap_key->id = id;
2769 ap_key->key_type = key_type;
2770 ap_key->key_size = key_size;
2771 memcpy(ap_key->key, key, key_size);
2772 ap_key->hlid = hlid;
2773 ap_key->tx_seq_32 = tx_seq_32;
2774 ap_key->tx_seq_16 = tx_seq_16;
2775
Eliad Peller170d0e62011-10-05 11:56:06 +02002776 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002777 return 0;
2778}
2779
Eliad Peller170d0e62011-10-05 11:56:06 +02002780static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002781{
2782 int i;
2783
2784 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002785 kfree(wlvif->ap.recorded_keys[i]);
2786 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002787 }
2788}
2789
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002790static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002791{
2792 int i, ret = 0;
2793 struct wl1271_ap_key *key;
2794 bool wep_key_added = false;
2795
2796 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002797 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002798 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002799 break;
2800
Eliad Peller170d0e62011-10-05 11:56:06 +02002801 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002802 hlid = key->hlid;
2803 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002804 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002805
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002806 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002807 key->id, key->key_type,
2808 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002809 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002810 key->tx_seq_16);
2811 if (ret < 0)
2812 goto out;
2813
2814 if (key->key_type == KEY_WEP)
2815 wep_key_added = true;
2816 }
2817
2818 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002819 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002820 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002821 if (ret < 0)
2822 goto out;
2823 }
2824
2825out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002826 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002827 return ret;
2828}
2829
Eliad Peller536129c2011-10-05 11:55:45 +02002830static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2831 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002832 u8 key_size, const u8 *key, u32 tx_seq_32,
2833 u16 tx_seq_16, struct ieee80211_sta *sta)
2834{
2835 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002836 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002837
2838 if (is_ap) {
2839 struct wl1271_station *wl_sta;
2840 u8 hlid;
2841
2842 if (sta) {
2843 wl_sta = (struct wl1271_station *)sta->drv_priv;
2844 hlid = wl_sta->hlid;
2845 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002846 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002847 }
2848
Eliad Peller53d40d02011-10-10 10:13:02 +02002849 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002850 /*
2851 * We do not support removing keys after AP shutdown.
2852 * Pretend we do to make mac80211 happy.
2853 */
2854 if (action != KEY_ADD_OR_REPLACE)
2855 return 0;
2856
Eliad Peller170d0e62011-10-05 11:56:06 +02002857 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002858 key_type, key_size,
2859 key, hlid, tx_seq_32,
2860 tx_seq_16);
2861 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002862 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002863 id, key_type, key_size,
2864 key, hlid, tx_seq_32,
2865 tx_seq_16);
2866 }
2867
2868 if (ret < 0)
2869 return ret;
2870 } else {
2871 const u8 *addr;
2872 static const u8 bcast_addr[ETH_ALEN] = {
2873 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2874 };
2875
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002876 /*
2877 * A STA set to GEM cipher requires 2 tx spare blocks.
2878 * Return to default value when GEM cipher key is removed
2879 */
2880 if (key_type == KEY_GEM) {
2881 if (action == KEY_ADD_OR_REPLACE)
2882 wl->tx_spare_blocks = 2;
2883 else if (action == KEY_REMOVE)
2884 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2885 }
2886
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002887 addr = sta ? sta->addr : bcast_addr;
2888
2889 if (is_zero_ether_addr(addr)) {
2890 /* We dont support TX only encryption */
2891 return -EOPNOTSUPP;
2892 }
2893
2894 /* The wl1271 does not allow to remove unicast keys - they
2895 will be cleared automatically on next CMD_JOIN. Ignore the
2896 request silently, as we dont want the mac80211 to emit
2897 an error message. */
2898 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2899 return 0;
2900
Eliad Peller010d3d32011-08-14 13:17:31 +03002901 /* don't remove key if hlid was already deleted */
2902 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002903 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002904 return 0;
2905
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002906 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002907 id, key_type, key_size,
2908 key, addr, tx_seq_32,
2909 tx_seq_16);
2910 if (ret < 0)
2911 return ret;
2912
2913 /* the default WEP key needs to be configured at least once */
2914 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002915 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002916 wlvif->default_key,
2917 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002918 if (ret < 0)
2919 return ret;
2920 }
2921 }
2922
2923 return 0;
2924}
2925
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002926static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2927 struct ieee80211_vif *vif,
2928 struct ieee80211_sta *sta,
2929 struct ieee80211_key_conf *key_conf)
2930{
2931 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002932 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002933 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002934 u32 tx_seq_32 = 0;
2935 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002936 u8 key_type;
2937
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002938 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2939
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002940 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002941 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002942 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002943 key_conf->keylen, key_conf->flags);
2944 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2945
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002946 mutex_lock(&wl->mutex);
2947
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002948 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2949 ret = -EAGAIN;
2950 goto out_unlock;
2951 }
2952
Ido Yariva6208652011-03-01 15:14:41 +02002953 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002954 if (ret < 0)
2955 goto out_unlock;
2956
Johannes Berg97359d12010-08-10 09:46:38 +02002957 switch (key_conf->cipher) {
2958 case WLAN_CIPHER_SUITE_WEP40:
2959 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002960 key_type = KEY_WEP;
2961
2962 key_conf->hw_key_idx = key_conf->keyidx;
2963 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002964 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002965 key_type = KEY_TKIP;
2966
2967 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002968 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2969 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002970 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002971 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002972 key_type = KEY_AES;
2973
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002974 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002975 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2976 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002977 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002978 case WL1271_CIPHER_SUITE_GEM:
2979 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002980 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2981 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002982 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002983 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002984 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002985
2986 ret = -EOPNOTSUPP;
2987 goto out_sleep;
2988 }
2989
2990 switch (cmd) {
2991 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002992 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002993 key_conf->keyidx, key_type,
2994 key_conf->keylen, key_conf->key,
2995 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002996 if (ret < 0) {
2997 wl1271_error("Could not add or replace key");
2998 goto out_sleep;
2999 }
3000 break;
3001
3002 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003003 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003004 key_conf->keyidx, key_type,
3005 key_conf->keylen, key_conf->key,
3006 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003007 if (ret < 0) {
3008 wl1271_error("Could not remove key");
3009 goto out_sleep;
3010 }
3011 break;
3012
3013 default:
3014 wl1271_error("Unsupported key cmd 0x%x", cmd);
3015 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003016 break;
3017 }
3018
3019out_sleep:
3020 wl1271_ps_elp_sleep(wl);
3021
3022out_unlock:
3023 mutex_unlock(&wl->mutex);
3024
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003025 return ret;
3026}
3027
3028static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003029 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003030 struct cfg80211_scan_request *req)
3031{
3032 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003033 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3034
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003035 int ret;
3036 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003037 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003038
3039 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3040
3041 if (req->n_ssids) {
3042 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003043 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003044 }
3045
3046 mutex_lock(&wl->mutex);
3047
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003048 if (wl->state == WL1271_STATE_OFF) {
3049 /*
3050 * We cannot return -EBUSY here because cfg80211 will expect
3051 * a call to ieee80211_scan_completed if we do - in this case
3052 * there won't be any call.
3053 */
3054 ret = -EAGAIN;
3055 goto out;
3056 }
3057
Ido Yariva6208652011-03-01 15:14:41 +02003058 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003059 if (ret < 0)
3060 goto out;
3061
Eliad Peller92e712d2011-12-18 20:25:43 +02003062 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
3063 test_bit(wlvif->role_id, wl->roc_map)) {
3064 /* don't allow scanning right now */
3065 ret = -EBUSY;
3066 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003067 }
3068
Eliad Peller92e712d2011-12-18 20:25:43 +02003069 /* cancel ROC before scanning */
3070 if (wl12xx_dev_role_started(wlvif))
3071 wl12xx_stop_dev(wl, wlvif);
3072
Eliad Peller784f6942011-10-05 11:55:39 +02003073 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003074out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003075 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003076out:
3077 mutex_unlock(&wl->mutex);
3078
3079 return ret;
3080}
3081
Eliad Peller73ecce32011-06-27 13:06:45 +03003082static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3083 struct ieee80211_vif *vif)
3084{
3085 struct wl1271 *wl = hw->priv;
3086 int ret;
3087
3088 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3089
3090 mutex_lock(&wl->mutex);
3091
3092 if (wl->state == WL1271_STATE_OFF)
3093 goto out;
3094
3095 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3096 goto out;
3097
3098 ret = wl1271_ps_elp_wakeup(wl);
3099 if (ret < 0)
3100 goto out;
3101
3102 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3103 ret = wl1271_scan_stop(wl);
3104 if (ret < 0)
3105 goto out_sleep;
3106 }
3107 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3108 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003109 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003110 wl->scan.req = NULL;
3111 ieee80211_scan_completed(wl->hw, true);
3112
3113out_sleep:
3114 wl1271_ps_elp_sleep(wl);
3115out:
3116 mutex_unlock(&wl->mutex);
3117
3118 cancel_delayed_work_sync(&wl->scan_complete_work);
3119}
3120
Luciano Coelho33c2c062011-05-10 14:46:02 +03003121static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3122 struct ieee80211_vif *vif,
3123 struct cfg80211_sched_scan_request *req,
3124 struct ieee80211_sched_scan_ies *ies)
3125{
3126 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003127 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003128 int ret;
3129
3130 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3131
3132 mutex_lock(&wl->mutex);
3133
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003134 if (wl->state == WL1271_STATE_OFF) {
3135 ret = -EAGAIN;
3136 goto out;
3137 }
3138
Luciano Coelho33c2c062011-05-10 14:46:02 +03003139 ret = wl1271_ps_elp_wakeup(wl);
3140 if (ret < 0)
3141 goto out;
3142
Eliad Peller536129c2011-10-05 11:55:45 +02003143 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003144 if (ret < 0)
3145 goto out_sleep;
3146
Eliad Peller536129c2011-10-05 11:55:45 +02003147 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003148 if (ret < 0)
3149 goto out_sleep;
3150
3151 wl->sched_scanning = true;
3152
3153out_sleep:
3154 wl1271_ps_elp_sleep(wl);
3155out:
3156 mutex_unlock(&wl->mutex);
3157 return ret;
3158}
3159
3160static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3161 struct ieee80211_vif *vif)
3162{
3163 struct wl1271 *wl = hw->priv;
3164 int ret;
3165
3166 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3167
3168 mutex_lock(&wl->mutex);
3169
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003170 if (wl->state == WL1271_STATE_OFF)
3171 goto out;
3172
Luciano Coelho33c2c062011-05-10 14:46:02 +03003173 ret = wl1271_ps_elp_wakeup(wl);
3174 if (ret < 0)
3175 goto out;
3176
3177 wl1271_scan_sched_scan_stop(wl);
3178
3179 wl1271_ps_elp_sleep(wl);
3180out:
3181 mutex_unlock(&wl->mutex);
3182}
3183
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003184static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3185{
3186 struct wl1271 *wl = hw->priv;
3187 int ret = 0;
3188
3189 mutex_lock(&wl->mutex);
3190
3191 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3192 ret = -EAGAIN;
3193 goto out;
3194 }
3195
Ido Yariva6208652011-03-01 15:14:41 +02003196 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003197 if (ret < 0)
3198 goto out;
3199
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003200 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003201 if (ret < 0)
3202 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3203
3204 wl1271_ps_elp_sleep(wl);
3205
3206out:
3207 mutex_unlock(&wl->mutex);
3208
3209 return ret;
3210}
3211
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003212static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3213{
3214 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003215 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003216 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003217
3218 mutex_lock(&wl->mutex);
3219
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003220 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3221 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003222 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003223 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003224
Ido Yariva6208652011-03-01 15:14:41 +02003225 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003226 if (ret < 0)
3227 goto out;
3228
Eliad Peller6e8cd332011-10-10 10:13:13 +02003229 wl12xx_for_each_wlvif(wl, wlvif) {
3230 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3231 if (ret < 0)
3232 wl1271_warning("set rts threshold failed: %d", ret);
3233 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003234 wl1271_ps_elp_sleep(wl);
3235
3236out:
3237 mutex_unlock(&wl->mutex);
3238
3239 return ret;
3240}
3241
Eliad Peller1fe9f162011-10-05 11:55:48 +02003242static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003243 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003244{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003245 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003246 u8 ssid_len;
3247 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3248 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003249
Eliad Peller889cb362011-05-01 09:56:45 +03003250 if (!ptr) {
3251 wl1271_error("No SSID in IEs!");
3252 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003253 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003254
Eliad Peller889cb362011-05-01 09:56:45 +03003255 ssid_len = ptr[1];
3256 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3257 wl1271_error("SSID is too long!");
3258 return -EINVAL;
3259 }
3260
Eliad Peller1fe9f162011-10-05 11:55:48 +02003261 wlvif->ssid_len = ssid_len;
3262 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003263 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003264}
3265
Eliad Pellerd48055d2011-09-15 12:07:04 +03003266static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3267{
3268 int len;
3269 const u8 *next, *end = skb->data + skb->len;
3270 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3271 skb->len - ieoffset);
3272 if (!ie)
3273 return;
3274 len = ie[1] + 2;
3275 next = ie + len;
3276 memmove(ie, next, end - next);
3277 skb_trim(skb, skb->len - len);
3278}
3279
Eliad Peller26b4bf22011-09-15 12:07:05 +03003280static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3281 unsigned int oui, u8 oui_type,
3282 int ieoffset)
3283{
3284 int len;
3285 const u8 *next, *end = skb->data + skb->len;
3286 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3287 skb->data + ieoffset,
3288 skb->len - ieoffset);
3289 if (!ie)
3290 return;
3291 len = ie[1] + 2;
3292 next = ie + len;
3293 memmove(ie, next, end - next);
3294 skb_trim(skb, skb->len - len);
3295}
3296
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003297static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3298 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003299{
3300 struct sk_buff *skb;
3301 int ret;
3302
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003303 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003304 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003305 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003306
3307 ret = wl1271_cmd_template_set(wl,
3308 CMD_TEMPL_AP_PROBE_RESPONSE,
3309 skb->data,
3310 skb->len, 0,
3311 rates);
3312
3313 dev_kfree_skb(skb);
3314 return ret;
3315}
3316
3317static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3318 struct ieee80211_vif *vif,
3319 u8 *probe_rsp_data,
3320 size_t probe_rsp_len,
3321 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003322{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003323 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3324 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003325 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3326 int ssid_ie_offset, ie_offset, templ_len;
3327 const u8 *ptr;
3328
3329 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003330 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003331 return wl1271_cmd_template_set(wl,
3332 CMD_TEMPL_AP_PROBE_RESPONSE,
3333 probe_rsp_data,
3334 probe_rsp_len, 0,
3335 rates);
3336
3337 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3338 wl1271_error("probe_rsp template too big");
3339 return -EINVAL;
3340 }
3341
3342 /* start searching from IE offset */
3343 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3344
3345 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3346 probe_rsp_len - ie_offset);
3347 if (!ptr) {
3348 wl1271_error("No SSID in beacon!");
3349 return -EINVAL;
3350 }
3351
3352 ssid_ie_offset = ptr - probe_rsp_data;
3353 ptr += (ptr[1] + 2);
3354
3355 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3356
3357 /* insert SSID from bss_conf */
3358 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3359 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3360 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3361 bss_conf->ssid, bss_conf->ssid_len);
3362 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3363
3364 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3365 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3366 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3367
3368 return wl1271_cmd_template_set(wl,
3369 CMD_TEMPL_AP_PROBE_RESPONSE,
3370 probe_rsp_templ,
3371 templ_len, 0,
3372 rates);
3373}
3374
Arik Nemtsove78a2872010-10-16 19:07:21 +02003375static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003376 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003377 struct ieee80211_bss_conf *bss_conf,
3378 u32 changed)
3379{
Eliad Peller0603d892011-10-05 11:55:51 +02003380 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003381 int ret = 0;
3382
3383 if (changed & BSS_CHANGED_ERP_SLOT) {
3384 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003385 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003386 else
Eliad Peller0603d892011-10-05 11:55:51 +02003387 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003388 if (ret < 0) {
3389 wl1271_warning("Set slot time failed %d", ret);
3390 goto out;
3391 }
3392 }
3393
3394 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3395 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003396 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003397 else
Eliad Peller0603d892011-10-05 11:55:51 +02003398 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003399 }
3400
3401 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3402 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003403 ret = wl1271_acx_cts_protect(wl, wlvif,
3404 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003405 else
Eliad Peller0603d892011-10-05 11:55:51 +02003406 ret = wl1271_acx_cts_protect(wl, wlvif,
3407 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003408 if (ret < 0) {
3409 wl1271_warning("Set ctsprotect failed %d", ret);
3410 goto out;
3411 }
3412 }
3413
3414out:
3415 return ret;
3416}
3417
3418static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3419 struct ieee80211_vif *vif,
3420 struct ieee80211_bss_conf *bss_conf,
3421 u32 changed)
3422{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003423 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003424 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003425 int ret = 0;
3426
3427 if ((changed & BSS_CHANGED_BEACON_INT)) {
3428 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3429 bss_conf->beacon_int);
3430
Eliad Peller6a899792011-10-05 11:55:58 +02003431 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003432 }
3433
Arik Nemtsov560f0022011-11-08 18:46:54 +02003434 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3435 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003436 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3437 wl1271_debug(DEBUG_AP, "probe response updated");
3438 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3439 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003440 }
3441
Arik Nemtsove78a2872010-10-16 19:07:21 +02003442 if ((changed & BSS_CHANGED_BEACON)) {
3443 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003444 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003445 int ieoffset = offsetof(struct ieee80211_mgmt,
3446 u.beacon.variable);
3447 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3448 u16 tmpl_id;
3449
Arik Nemtsov560f0022011-11-08 18:46:54 +02003450 if (!beacon) {
3451 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003452 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003453 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003454
3455 wl1271_debug(DEBUG_MASTER, "beacon updated");
3456
Eliad Peller1fe9f162011-10-05 11:55:48 +02003457 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003458 if (ret < 0) {
3459 dev_kfree_skb(beacon);
3460 goto out;
3461 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003462 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003463 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3464 CMD_TEMPL_BEACON;
3465 ret = wl1271_cmd_template_set(wl, tmpl_id,
3466 beacon->data,
3467 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003468 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003469 if (ret < 0) {
3470 dev_kfree_skb(beacon);
3471 goto out;
3472 }
3473
Arik Nemtsov560f0022011-11-08 18:46:54 +02003474 /*
3475 * In case we already have a probe-resp beacon set explicitly
3476 * by usermode, don't use the beacon data.
3477 */
3478 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3479 goto end_bcn;
3480
Eliad Pellerd48055d2011-09-15 12:07:04 +03003481 /* remove TIM ie from probe response */
3482 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3483
Eliad Peller26b4bf22011-09-15 12:07:05 +03003484 /*
3485 * remove p2p ie from probe response.
3486 * the fw reponds to probe requests that don't include
3487 * the p2p ie. probe requests with p2p ie will be passed,
3488 * and will be responded by the supplicant (the spec
3489 * forbids including the p2p ie when responding to probe
3490 * requests that didn't include it).
3491 */
3492 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3493 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3494
Arik Nemtsove78a2872010-10-16 19:07:21 +02003495 hdr = (struct ieee80211_hdr *) beacon->data;
3496 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3497 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003498 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003499 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003500 beacon->data,
3501 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003502 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003503 else
3504 ret = wl1271_cmd_template_set(wl,
3505 CMD_TEMPL_PROBE_RESPONSE,
3506 beacon->data,
3507 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003508 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003509end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003510 dev_kfree_skb(beacon);
3511 if (ret < 0)
3512 goto out;
3513 }
3514
3515out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003516 if (ret != 0)
3517 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003518 return ret;
3519}
3520
3521/* AP mode changes */
3522static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003523 struct ieee80211_vif *vif,
3524 struct ieee80211_bss_conf *bss_conf,
3525 u32 changed)
3526{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003527 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003528 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003529
Arik Nemtsove78a2872010-10-16 19:07:21 +02003530 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3531 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003532
Eliad Peller87fbcb02011-10-05 11:55:41 +02003533 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003534 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003535 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003536 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003537
Eliad Peller87fbcb02011-10-05 11:55:41 +02003538 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003539 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003540 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003541 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003542 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003543
Eliad Peller784f6942011-10-05 11:55:39 +02003544 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003545 if (ret < 0)
3546 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003547 }
3548
Arik Nemtsove78a2872010-10-16 19:07:21 +02003549 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3550 if (ret < 0)
3551 goto out;
3552
3553 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3554 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003555 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003556 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003557 if (ret < 0)
3558 goto out;
3559
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003560 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003561 if (ret < 0)
3562 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003563
Eliad Peller53d40d02011-10-10 10:13:02 +02003564 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003565 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003566 }
3567 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003568 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003569 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003570 if (ret < 0)
3571 goto out;
3572
Eliad Peller53d40d02011-10-10 10:13:02 +02003573 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003574 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3575 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003576 wl1271_debug(DEBUG_AP, "stopped AP");
3577 }
3578 }
3579 }
3580
Eliad Peller0603d892011-10-05 11:55:51 +02003581 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003582 if (ret < 0)
3583 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003584
3585 /* Handle HT information change */
3586 if ((changed & BSS_CHANGED_HT) &&
3587 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003588 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003589 bss_conf->ht_operation_mode);
3590 if (ret < 0) {
3591 wl1271_warning("Set ht information failed %d", ret);
3592 goto out;
3593 }
3594 }
3595
Arik Nemtsove78a2872010-10-16 19:07:21 +02003596out:
3597 return;
3598}
3599
3600/* STA/IBSS mode changes */
3601static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3602 struct ieee80211_vif *vif,
3603 struct ieee80211_bss_conf *bss_conf,
3604 u32 changed)
3605{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003606 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003607 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003608 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003609 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003610 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003611 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003612 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003613 bool sta_exists = false;
3614 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003615
3616 if (is_ibss) {
3617 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3618 changed);
3619 if (ret < 0)
3620 goto out;
3621 }
3622
Eliad Peller227e81e2011-08-14 13:17:26 +03003623 if (changed & BSS_CHANGED_IBSS) {
3624 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003625 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003626 ibss_joined = true;
3627 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003628 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3629 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003630 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003631 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003632 }
3633 }
3634 }
3635
3636 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003637 do_join = true;
3638
3639 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003640 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003641 do_join = true;
3642
Eliad Peller227e81e2011-08-14 13:17:26 +03003643 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003644 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3645 bss_conf->enable_beacon ? "enabled" : "disabled");
3646
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003647 do_join = true;
3648 }
3649
Eliad Pellerc31e4942011-10-23 08:21:55 +02003650 if (changed & BSS_CHANGED_IDLE) {
3651 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3652 if (ret < 0)
3653 wl1271_warning("idle mode change failed %d", ret);
3654 }
3655
Arik Nemtsove78a2872010-10-16 19:07:21 +02003656 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003657 bool enable = false;
3658 if (bss_conf->cqm_rssi_thold)
3659 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003660 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003661 bss_conf->cqm_rssi_thold,
3662 bss_conf->cqm_rssi_hyst);
3663 if (ret < 0)
3664 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003665 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003666 }
3667
Eliad Peller7db4ee62012-01-24 18:18:42 +02003668 if (changed & BSS_CHANGED_BSSID &&
3669 (is_ibss || bss_conf->assoc))
Eliad Pellercdf09492011-10-05 11:55:44 +02003670 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003671 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003672 if (ret < 0)
3673 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003674
Eliad Peller784f6942011-10-05 11:55:39 +02003675 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003676 if (ret < 0)
3677 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003678
Eliad Pellerfa287b82010-12-26 09:27:50 +01003679 /* Need to update the BSSID (for filtering etc) */
3680 do_join = true;
3681 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003682
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003683 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3684 rcu_read_lock();
3685 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3686 if (!sta)
3687 goto sta_not_found;
3688
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003689 /* save the supp_rates of the ap */
3690 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3691 if (sta->ht_cap.ht_supported)
3692 sta_rate_set |=
3693 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003694 sta_ht_cap = sta->ht_cap;
3695 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003696
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003697sta_not_found:
3698 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003699 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003700
Arik Nemtsove78a2872010-10-16 19:07:21 +02003701 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003702 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003703 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003704 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003705 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003706 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003707
Eliad Peller74ec8392011-10-05 11:56:02 +02003708 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003709
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003710 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003711 * use basic rates from AP, and determine lowest rate
3712 * to use with control frames.
3713 */
3714 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003715 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003716 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003717 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003718 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003719 wl1271_tx_min_rate_get(wl,
3720 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003721 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003722 wlvif->rate_set =
3723 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003724 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003725 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003726 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003727 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003728 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003729
3730 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003731 * with wl1271, we don't need to update the
3732 * beacon_int and dtim_period, because the firmware
3733 * updates it by itself when the first beacon is
3734 * received after a join.
3735 */
Eliad Peller6840e372011-10-05 11:55:50 +02003736 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003737 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003738 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003739
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003740 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003741 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003742 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003743 dev_kfree_skb(wlvif->probereq);
3744 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003745 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003746 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003747 ieoffset = offsetof(struct ieee80211_mgmt,
3748 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003749 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003750
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003751 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003752 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003753 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003754 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003755 } else {
3756 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003757 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003758 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3759 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003760 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003761 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3762 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003763 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003764
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003765 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003766 dev_kfree_skb(wlvif->probereq);
3767 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003768
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003769 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003770 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003771
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003772 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003773 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003774 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003775 wl1271_tx_min_rate_get(wl,
3776 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003777 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003778 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003779 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003780
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003781 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003782 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003783
3784 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003785 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003786 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003787 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003788
3789 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003790 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003791 u32 conf_flags = wl->hw->conf.flags;
3792 /*
3793 * we might have to disable roc, if there was
3794 * no IF_OPER_UP notification.
3795 */
3796 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003797 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003798 if (ret < 0)
3799 goto out;
3800 }
3801 /*
3802 * (we also need to disable roc in case of
3803 * roaming on the same channel. until we will
3804 * have a better flow...)
3805 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003806 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3807 ret = wl12xx_croc(wl,
3808 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003809 if (ret < 0)
3810 goto out;
3811 }
3812
Eliad Peller0603d892011-10-05 11:55:51 +02003813 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003814 if (!(conf_flags & IEEE80211_CONF_IDLE))
3815 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003816 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003817 }
3818 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003819
Eliad Pellerd192d262011-05-24 14:33:08 +03003820 if (changed & BSS_CHANGED_IBSS) {
3821 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3822 bss_conf->ibss_joined);
3823
3824 if (bss_conf->ibss_joined) {
3825 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003826 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003827 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003828 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003829 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003830 wl1271_tx_min_rate_get(wl,
3831 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003832
Shahar Levi06b660e2011-09-05 13:54:36 +03003833 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003834 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3835 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003836 if (ret < 0)
3837 goto out;
3838 }
3839 }
3840
Eliad Peller0603d892011-10-05 11:55:51 +02003841 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003842 if (ret < 0)
3843 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003844
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003845 if (changed & BSS_CHANGED_ARP_FILTER) {
3846 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003847 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003848
Eliad Pellerc5312772010-12-09 11:31:27 +02003849 if (bss_conf->arp_addr_cnt == 1 &&
3850 bss_conf->arp_filter_enabled) {
3851 /*
3852 * The template should have been configured only upon
3853 * association. however, it seems that the correct ip
3854 * isn't being set (when sending), so we have to
3855 * reconfigure the template upon every ip change.
3856 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003857 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003858 if (ret < 0) {
3859 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003860 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003861 }
3862
Eliad Peller0603d892011-10-05 11:55:51 +02003863 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003864 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003865 addr);
3866 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003867 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003868
3869 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003870 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003871 }
3872
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003873 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003874 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003875 if (ret < 0) {
3876 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003877 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003878 }
Eliad Peller251c1772011-08-14 13:17:17 +03003879
3880 /* ROC until connected (after EAPOL exchange) */
3881 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003882 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003883 if (ret < 0)
3884 goto out;
3885
Eliad Pellerba8447f2011-10-10 10:13:00 +02003886 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003887 ieee80211_get_operstate(vif));
3888 }
3889 /*
3890 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003891 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003892 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003893 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003894 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003895 if (ret < 0)
3896 goto out;
3897 }
Eliad Peller05dba352011-08-23 16:37:01 +03003898
3899 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003900 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3901 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003902 enum wl1271_cmd_ps_mode mode;
3903
3904 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003905 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003906 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003907 true);
3908 if (ret < 0)
3909 goto out;
3910 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003911 }
3912
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003913 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003914 if (sta_exists) {
3915 if ((changed & BSS_CHANGED_HT) &&
3916 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003917 ret = wl1271_acx_set_ht_capabilities(wl,
3918 &sta_ht_cap,
3919 true,
Eliad Peller154da672011-10-05 11:55:53 +02003920 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003921 if (ret < 0) {
3922 wl1271_warning("Set ht cap true failed %d",
3923 ret);
3924 goto out;
3925 }
3926 }
3927 /* handle new association without HT and disassociation */
3928 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003929 ret = wl1271_acx_set_ht_capabilities(wl,
3930 &sta_ht_cap,
3931 false,
Eliad Peller154da672011-10-05 11:55:53 +02003932 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003933 if (ret < 0) {
3934 wl1271_warning("Set ht cap false failed %d",
3935 ret);
3936 goto out;
3937 }
3938 }
3939 }
3940
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003941 /* Handle HT information change. Done after join. */
3942 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003943 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003944 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003945 bss_conf->ht_operation_mode);
3946 if (ret < 0) {
3947 wl1271_warning("Set ht information failed %d", ret);
3948 goto out;
3949 }
3950 }
3951
Arik Nemtsove78a2872010-10-16 19:07:21 +02003952out:
3953 return;
3954}
3955
3956static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3957 struct ieee80211_vif *vif,
3958 struct ieee80211_bss_conf *bss_conf,
3959 u32 changed)
3960{
3961 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003962 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3963 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003964 int ret;
3965
3966 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3967 (int)changed);
3968
3969 mutex_lock(&wl->mutex);
3970
3971 if (unlikely(wl->state == WL1271_STATE_OFF))
3972 goto out;
3973
Eliad Peller10c8cd02011-10-10 10:13:06 +02003974 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3975 goto out;
3976
Ido Yariva6208652011-03-01 15:14:41 +02003977 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003978 if (ret < 0)
3979 goto out;
3980
3981 if (is_ap)
3982 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3983 else
3984 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3985
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003986 wl1271_ps_elp_sleep(wl);
3987
3988out:
3989 mutex_unlock(&wl->mutex);
3990}
3991
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003992static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3993 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003994 const struct ieee80211_tx_queue_params *params)
3995{
3996 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003997 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003998 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003999 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02004000
4001 mutex_lock(&wl->mutex);
4002
4003 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
4004
Kalle Valo4695dc92010-03-18 12:26:38 +02004005 if (params->uapsd)
4006 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
4007 else
4008 ps_scheme = CONF_PS_SCHEME_LEGACY;
4009
Eliad Peller5b37ddf2011-12-18 20:25:40 +02004010 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004011 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004012
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004013 ret = wl1271_ps_elp_wakeup(wl);
4014 if (ret < 0)
4015 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004016
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004017 /*
4018 * the txop is confed in units of 32us by the mac80211,
4019 * we need us
4020 */
Eliad Peller0603d892011-10-05 11:55:51 +02004021 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004022 params->cw_min, params->cw_max,
4023 params->aifs, params->txop << 5);
4024 if (ret < 0)
4025 goto out_sleep;
4026
Eliad Peller0603d892011-10-05 11:55:51 +02004027 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004028 CONF_CHANNEL_TYPE_EDCF,
4029 wl1271_tx_get_queue(queue),
4030 ps_scheme, CONF_ACK_POLICY_LEGACY,
4031 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004032
4033out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004034 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004035
4036out:
4037 mutex_unlock(&wl->mutex);
4038
4039 return ret;
4040}
4041
Eliad Peller37a41b42011-09-21 14:06:11 +03004042static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4043 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004044{
4045
4046 struct wl1271 *wl = hw->priv;
4047 u64 mactime = ULLONG_MAX;
4048 int ret;
4049
4050 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4051
4052 mutex_lock(&wl->mutex);
4053
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004054 if (unlikely(wl->state == WL1271_STATE_OFF))
4055 goto out;
4056
Ido Yariva6208652011-03-01 15:14:41 +02004057 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004058 if (ret < 0)
4059 goto out;
4060
4061 ret = wl1271_acx_tsf_info(wl, &mactime);
4062 if (ret < 0)
4063 goto out_sleep;
4064
4065out_sleep:
4066 wl1271_ps_elp_sleep(wl);
4067
4068out:
4069 mutex_unlock(&wl->mutex);
4070 return mactime;
4071}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004072
John W. Linvilleece550d2010-07-28 16:41:06 -04004073static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4074 struct survey_info *survey)
4075{
4076 struct wl1271 *wl = hw->priv;
4077 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004078
John W. Linvilleece550d2010-07-28 16:41:06 -04004079 if (idx != 0)
4080 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004081
John W. Linvilleece550d2010-07-28 16:41:06 -04004082 survey->channel = conf->channel;
4083 survey->filled = SURVEY_INFO_NOISE_DBM;
4084 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004085
John W. Linvilleece550d2010-07-28 16:41:06 -04004086 return 0;
4087}
4088
Arik Nemtsov409622e2011-02-23 00:22:29 +02004089static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004090 struct wl12xx_vif *wlvif,
4091 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004092{
4093 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004094 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004095
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004096
4097 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004098 wl1271_warning("could not allocate HLID - too much stations");
4099 return -EBUSY;
4100 }
4101
4102 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004103 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4104 if (ret < 0) {
4105 wl1271_warning("could not allocate HLID - too many links");
4106 return -EBUSY;
4107 }
4108
4109 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004110 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004111 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004112 return 0;
4113}
4114
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004115void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004116{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004117 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004118 return;
4119
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004120 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004121 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004122 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004123 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004124 __clear_bit(hlid, &wl->ap_ps_map);
4125 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004126 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004127 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004128}
4129
4130static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4131 struct ieee80211_vif *vif,
4132 struct ieee80211_sta *sta)
4133{
4134 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004135 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004136 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004137 int ret = 0;
4138 u8 hlid;
4139
4140 mutex_lock(&wl->mutex);
4141
4142 if (unlikely(wl->state == WL1271_STATE_OFF))
4143 goto out;
4144
Eliad Peller536129c2011-10-05 11:55:45 +02004145 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004146 goto out;
4147
4148 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4149
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004150 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004151 if (ret < 0)
4152 goto out;
4153
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004154 wl_sta = (struct wl1271_station *)sta->drv_priv;
4155 hlid = wl_sta->hlid;
4156
Ido Yariva6208652011-03-01 15:14:41 +02004157 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004158 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004159 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004160
Eliad Peller1b92f152011-10-10 10:13:09 +02004161 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004162 if (ret < 0)
4163 goto out_sleep;
4164
Eliad Pellerb67476e2011-08-14 13:17:23 +03004165 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4166 if (ret < 0)
4167 goto out_sleep;
4168
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004169 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4170 if (ret < 0)
4171 goto out_sleep;
4172
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004173out_sleep:
4174 wl1271_ps_elp_sleep(wl);
4175
Arik Nemtsov409622e2011-02-23 00:22:29 +02004176out_free_sta:
4177 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004178 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004179
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004180out:
4181 mutex_unlock(&wl->mutex);
4182 return ret;
4183}
4184
4185static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4186 struct ieee80211_vif *vif,
4187 struct ieee80211_sta *sta)
4188{
4189 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004190 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004191 struct wl1271_station *wl_sta;
4192 int ret = 0, id;
4193
4194 mutex_lock(&wl->mutex);
4195
4196 if (unlikely(wl->state == WL1271_STATE_OFF))
4197 goto out;
4198
Eliad Peller536129c2011-10-05 11:55:45 +02004199 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004200 goto out;
4201
4202 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4203
4204 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004205 id = wl_sta->hlid;
4206 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004207 goto out;
4208
Ido Yariva6208652011-03-01 15:14:41 +02004209 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004210 if (ret < 0)
4211 goto out;
4212
Eliad Pellerc690ec82011-08-14 13:17:07 +03004213 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004214 if (ret < 0)
4215 goto out_sleep;
4216
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004217 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004218
4219out_sleep:
4220 wl1271_ps_elp_sleep(wl);
4221
4222out:
4223 mutex_unlock(&wl->mutex);
4224 return ret;
4225}
4226
Luciano Coelho4623ec72011-03-21 19:26:41 +02004227static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4228 struct ieee80211_vif *vif,
4229 enum ieee80211_ampdu_mlme_action action,
4230 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4231 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004232{
4233 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004234 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004235 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004236 u8 hlid, *ba_bitmap;
4237
4238 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4239 tid);
4240
4241 /* sanity check - the fields in FW are only 8bits wide */
4242 if (WARN_ON(tid > 0xFF))
4243 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004244
4245 mutex_lock(&wl->mutex);
4246
4247 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4248 ret = -EAGAIN;
4249 goto out;
4250 }
4251
Eliad Peller536129c2011-10-05 11:55:45 +02004252 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004253 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004254 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004255 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004256 struct wl1271_station *wl_sta;
4257
4258 wl_sta = (struct wl1271_station *)sta->drv_priv;
4259 hlid = wl_sta->hlid;
4260 ba_bitmap = &wl->links[hlid].ba_bitmap;
4261 } else {
4262 ret = -EINVAL;
4263 goto out;
4264 }
4265
Ido Yariva6208652011-03-01 15:14:41 +02004266 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004267 if (ret < 0)
4268 goto out;
4269
Shahar Levi70559a02011-05-22 16:10:22 +03004270 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4271 tid, action);
4272
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004273 switch (action) {
4274 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004275 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004276 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004277 break;
4278 }
4279
4280 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4281 ret = -EBUSY;
4282 wl1271_error("exceeded max RX BA sessions");
4283 break;
4284 }
4285
4286 if (*ba_bitmap & BIT(tid)) {
4287 ret = -EINVAL;
4288 wl1271_error("cannot enable RX BA session on active "
4289 "tid: %d", tid);
4290 break;
4291 }
4292
4293 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4294 hlid);
4295 if (!ret) {
4296 *ba_bitmap |= BIT(tid);
4297 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004298 }
4299 break;
4300
4301 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004302 if (!(*ba_bitmap & BIT(tid))) {
4303 ret = -EINVAL;
4304 wl1271_error("no active RX BA session on tid: %d",
4305 tid);
4306 break;
4307 }
4308
4309 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4310 hlid);
4311 if (!ret) {
4312 *ba_bitmap &= ~BIT(tid);
4313 wl->ba_rx_session_count--;
4314 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004315 break;
4316
4317 /*
4318 * The BA initiator session management in FW independently.
4319 * Falling break here on purpose for all TX APDU commands.
4320 */
4321 case IEEE80211_AMPDU_TX_START:
4322 case IEEE80211_AMPDU_TX_STOP:
4323 case IEEE80211_AMPDU_TX_OPERATIONAL:
4324 ret = -EINVAL;
4325 break;
4326
4327 default:
4328 wl1271_error("Incorrect ampdu action id=%x\n", action);
4329 ret = -EINVAL;
4330 }
4331
4332 wl1271_ps_elp_sleep(wl);
4333
4334out:
4335 mutex_unlock(&wl->mutex);
4336
4337 return ret;
4338}
4339
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004340static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4341 struct ieee80211_vif *vif,
4342 const struct cfg80211_bitrate_mask *mask)
4343{
Eliad Peller83587502011-10-10 10:12:53 +02004344 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004345 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004346 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004347
4348 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4349 mask->control[NL80211_BAND_2GHZ].legacy,
4350 mask->control[NL80211_BAND_5GHZ].legacy);
4351
4352 mutex_lock(&wl->mutex);
4353
4354 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004355 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004356 wl1271_tx_enabled_rates_get(wl,
4357 mask->control[i].legacy,
4358 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004359
4360 if (unlikely(wl->state == WL1271_STATE_OFF))
4361 goto out;
4362
4363 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4364 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4365
4366 ret = wl1271_ps_elp_wakeup(wl);
4367 if (ret < 0)
4368 goto out;
4369
4370 wl1271_set_band_rate(wl, wlvif);
4371 wlvif->basic_rate =
4372 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4373 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4374
4375 wl1271_ps_elp_sleep(wl);
4376 }
4377out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004378 mutex_unlock(&wl->mutex);
4379
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004380 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004381}
4382
Shahar Levi6d158ff2011-09-08 13:01:33 +03004383static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4384 struct ieee80211_channel_switch *ch_switch)
4385{
4386 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004387 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004388 int ret;
4389
4390 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4391
4392 mutex_lock(&wl->mutex);
4393
4394 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004395 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4396 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4397 ieee80211_chswitch_done(vif, false);
4398 }
4399 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004400 }
4401
4402 ret = wl1271_ps_elp_wakeup(wl);
4403 if (ret < 0)
4404 goto out;
4405
Eliad Peller52630c52011-10-10 10:13:08 +02004406 /* TODO: change mac80211 to pass vif as param */
4407 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4408 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004409
Eliad Peller52630c52011-10-10 10:13:08 +02004410 if (!ret)
4411 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4412 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004413
4414 wl1271_ps_elp_sleep(wl);
4415
4416out:
4417 mutex_unlock(&wl->mutex);
4418}
4419
Arik Nemtsov33437892011-04-26 23:35:39 +03004420static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4421{
4422 struct wl1271 *wl = hw->priv;
4423 bool ret = false;
4424
4425 mutex_lock(&wl->mutex);
4426
4427 if (unlikely(wl->state == WL1271_STATE_OFF))
4428 goto out;
4429
4430 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004431 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004432out:
4433 mutex_unlock(&wl->mutex);
4434
4435 return ret;
4436}
4437
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004438/* can't be const, mac80211 writes to this */
4439static struct ieee80211_rate wl1271_rates[] = {
4440 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004441 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4442 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004443 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004444 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4445 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004446 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4447 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004448 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4449 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004450 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4451 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004452 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4453 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004454 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4455 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004456 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4457 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004458 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004459 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4460 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004461 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004462 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4463 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004464 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004465 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4466 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004467 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004468 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4469 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004470 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004471 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4472 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004473 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004474 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4475 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004476 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004477 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4478 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004479};
4480
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004481/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004482static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004483 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004484 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004485 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4486 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4487 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004488 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004489 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4490 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4491 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004492 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004493 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4494 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4495 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004496 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004497};
4498
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004499/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004500static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004501 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004502 7, /* CONF_HW_RXTX_RATE_MCS7 */
4503 6, /* CONF_HW_RXTX_RATE_MCS6 */
4504 5, /* CONF_HW_RXTX_RATE_MCS5 */
4505 4, /* CONF_HW_RXTX_RATE_MCS4 */
4506 3, /* CONF_HW_RXTX_RATE_MCS3 */
4507 2, /* CONF_HW_RXTX_RATE_MCS2 */
4508 1, /* CONF_HW_RXTX_RATE_MCS1 */
4509 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004510
4511 11, /* CONF_HW_RXTX_RATE_54 */
4512 10, /* CONF_HW_RXTX_RATE_48 */
4513 9, /* CONF_HW_RXTX_RATE_36 */
4514 8, /* CONF_HW_RXTX_RATE_24 */
4515
4516 /* TI-specific rate */
4517 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4518
4519 7, /* CONF_HW_RXTX_RATE_18 */
4520 6, /* CONF_HW_RXTX_RATE_12 */
4521 3, /* CONF_HW_RXTX_RATE_11 */
4522 5, /* CONF_HW_RXTX_RATE_9 */
4523 4, /* CONF_HW_RXTX_RATE_6 */
4524 2, /* CONF_HW_RXTX_RATE_5_5 */
4525 1, /* CONF_HW_RXTX_RATE_2 */
4526 0 /* CONF_HW_RXTX_RATE_1 */
4527};
4528
Shahar Levie8b03a22010-10-13 16:09:39 +02004529/* 11n STA capabilities */
4530#define HW_RX_HIGHEST_RATE 72
4531
Shahar Levi00d20102010-11-08 11:20:10 +00004532#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004533 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4534 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004535 .ht_supported = true, \
4536 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4537 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4538 .mcs = { \
4539 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4540 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4541 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4542 }, \
4543}
4544
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004545/* can't be const, mac80211 writes to this */
4546static struct ieee80211_supported_band wl1271_band_2ghz = {
4547 .channels = wl1271_channels,
4548 .n_channels = ARRAY_SIZE(wl1271_channels),
4549 .bitrates = wl1271_rates,
4550 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004551 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004552};
4553
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004554/* 5 GHz data rates for WL1273 */
4555static struct ieee80211_rate wl1271_rates_5ghz[] = {
4556 { .bitrate = 60,
4557 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4558 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4559 { .bitrate = 90,
4560 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4561 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4562 { .bitrate = 120,
4563 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4564 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4565 { .bitrate = 180,
4566 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4567 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4568 { .bitrate = 240,
4569 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4570 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4571 { .bitrate = 360,
4572 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4573 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4574 { .bitrate = 480,
4575 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4576 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4577 { .bitrate = 540,
4578 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4579 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4580};
4581
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004582/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004583static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004584 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4585 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4586 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4587 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4588 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4589 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4590 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4591 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4592 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4593 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4594 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4595 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4596 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4597 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4598 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4599 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4600 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4601 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4602 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4603 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4604 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4605 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4606 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4607 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4608 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4609 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4610 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4611 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4612 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4613 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4614 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4615 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4616 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4617 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004618};
4619
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004620/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004621static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004622 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004623 7, /* CONF_HW_RXTX_RATE_MCS7 */
4624 6, /* CONF_HW_RXTX_RATE_MCS6 */
4625 5, /* CONF_HW_RXTX_RATE_MCS5 */
4626 4, /* CONF_HW_RXTX_RATE_MCS4 */
4627 3, /* CONF_HW_RXTX_RATE_MCS3 */
4628 2, /* CONF_HW_RXTX_RATE_MCS2 */
4629 1, /* CONF_HW_RXTX_RATE_MCS1 */
4630 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004631
4632 7, /* CONF_HW_RXTX_RATE_54 */
4633 6, /* CONF_HW_RXTX_RATE_48 */
4634 5, /* CONF_HW_RXTX_RATE_36 */
4635 4, /* CONF_HW_RXTX_RATE_24 */
4636
4637 /* TI-specific rate */
4638 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4639
4640 3, /* CONF_HW_RXTX_RATE_18 */
4641 2, /* CONF_HW_RXTX_RATE_12 */
4642 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4643 1, /* CONF_HW_RXTX_RATE_9 */
4644 0, /* CONF_HW_RXTX_RATE_6 */
4645 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4646 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4647 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4648};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004649
4650static struct ieee80211_supported_band wl1271_band_5ghz = {
4651 .channels = wl1271_channels_5ghz,
4652 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4653 .bitrates = wl1271_rates_5ghz,
4654 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004655 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004656};
4657
Tobias Klausera0ea9492010-05-20 10:38:11 +02004658static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004659 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4660 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4661};
4662
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004663static const struct ieee80211_ops wl1271_ops = {
4664 .start = wl1271_op_start,
4665 .stop = wl1271_op_stop,
4666 .add_interface = wl1271_op_add_interface,
4667 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004668 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004669#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004670 .suspend = wl1271_op_suspend,
4671 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004672#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004673 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004674 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004675 .configure_filter = wl1271_op_configure_filter,
4676 .tx = wl1271_op_tx,
4677 .set_key = wl1271_op_set_key,
4678 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004679 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004680 .sched_scan_start = wl1271_op_sched_scan_start,
4681 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004682 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004683 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004684 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004685 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004686 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004687 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004688 .sta_add = wl1271_op_sta_add,
4689 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004690 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004691 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004692 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004693 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004694 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004695};
4696
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004697
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004698u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004699{
4700 u8 idx;
4701
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004702 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004703
4704 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4705 wl1271_error("Illegal RX rate from HW: %d", rate);
4706 return 0;
4707 }
4708
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004709 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004710 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4711 wl1271_error("Unsupported RX rate from HW: %d", rate);
4712 return 0;
4713 }
4714
4715 return idx;
4716}
4717
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004718static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4719 struct device_attribute *attr,
4720 char *buf)
4721{
4722 struct wl1271 *wl = dev_get_drvdata(dev);
4723 ssize_t len;
4724
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004725 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004726
4727 mutex_lock(&wl->mutex);
4728 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4729 wl->sg_enabled);
4730 mutex_unlock(&wl->mutex);
4731
4732 return len;
4733
4734}
4735
4736static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4737 struct device_attribute *attr,
4738 const char *buf, size_t count)
4739{
4740 struct wl1271 *wl = dev_get_drvdata(dev);
4741 unsigned long res;
4742 int ret;
4743
Luciano Coelho6277ed62011-04-01 17:49:54 +03004744 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004745 if (ret < 0) {
4746 wl1271_warning("incorrect value written to bt_coex_mode");
4747 return count;
4748 }
4749
4750 mutex_lock(&wl->mutex);
4751
4752 res = !!res;
4753
4754 if (res == wl->sg_enabled)
4755 goto out;
4756
4757 wl->sg_enabled = res;
4758
4759 if (wl->state == WL1271_STATE_OFF)
4760 goto out;
4761
Ido Yariva6208652011-03-01 15:14:41 +02004762 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004763 if (ret < 0)
4764 goto out;
4765
4766 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4767 wl1271_ps_elp_sleep(wl);
4768
4769 out:
4770 mutex_unlock(&wl->mutex);
4771 return count;
4772}
4773
4774static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4775 wl1271_sysfs_show_bt_coex_state,
4776 wl1271_sysfs_store_bt_coex_state);
4777
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004778static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4779 struct device_attribute *attr,
4780 char *buf)
4781{
4782 struct wl1271 *wl = dev_get_drvdata(dev);
4783 ssize_t len;
4784
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004785 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004786
4787 mutex_lock(&wl->mutex);
4788 if (wl->hw_pg_ver >= 0)
4789 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4790 else
4791 len = snprintf(buf, len, "n/a\n");
4792 mutex_unlock(&wl->mutex);
4793
4794 return len;
4795}
4796
Gery Kahn6f07b722011-07-18 14:21:49 +03004797static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004798 wl1271_sysfs_show_hw_pg_ver, NULL);
4799
Ido Yariv95dac04f2011-06-06 14:57:06 +03004800static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4801 struct bin_attribute *bin_attr,
4802 char *buffer, loff_t pos, size_t count)
4803{
4804 struct device *dev = container_of(kobj, struct device, kobj);
4805 struct wl1271 *wl = dev_get_drvdata(dev);
4806 ssize_t len;
4807 int ret;
4808
4809 ret = mutex_lock_interruptible(&wl->mutex);
4810 if (ret < 0)
4811 return -ERESTARTSYS;
4812
4813 /* Let only one thread read the log at a time, blocking others */
4814 while (wl->fwlog_size == 0) {
4815 DEFINE_WAIT(wait);
4816
4817 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4818 &wait,
4819 TASK_INTERRUPTIBLE);
4820
4821 if (wl->fwlog_size != 0) {
4822 finish_wait(&wl->fwlog_waitq, &wait);
4823 break;
4824 }
4825
4826 mutex_unlock(&wl->mutex);
4827
4828 schedule();
4829 finish_wait(&wl->fwlog_waitq, &wait);
4830
4831 if (signal_pending(current))
4832 return -ERESTARTSYS;
4833
4834 ret = mutex_lock_interruptible(&wl->mutex);
4835 if (ret < 0)
4836 return -ERESTARTSYS;
4837 }
4838
4839 /* Check if the fwlog is still valid */
4840 if (wl->fwlog_size < 0) {
4841 mutex_unlock(&wl->mutex);
4842 return 0;
4843 }
4844
4845 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4846 len = min(count, (size_t)wl->fwlog_size);
4847 wl->fwlog_size -= len;
4848 memcpy(buffer, wl->fwlog, len);
4849
4850 /* Make room for new messages */
4851 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4852
4853 mutex_unlock(&wl->mutex);
4854
4855 return len;
4856}
4857
4858static struct bin_attribute fwlog_attr = {
4859 .attr = {.name = "fwlog", .mode = S_IRUSR},
4860 .read = wl1271_sysfs_read_fwlog,
4861};
4862
Luciano Coelho5e037e72011-12-23 09:32:17 +02004863static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
4864{
4865 bool supported = false;
4866 u8 major, minor;
4867
4868 if (wl->chip.id == CHIP_ID_1283_PG20) {
4869 major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
4870 minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
4871
4872 /* in wl128x we have the MAC address if the PG is >= (2, 1) */
4873 if (major > 2 || (major == 2 && minor >= 1))
4874 supported = true;
4875 } else {
4876 major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
4877 minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
4878
4879 /* in wl127x we have the MAC address if the PG is >= (3, 1) */
4880 if (major == 3 && minor >= 1)
4881 supported = true;
4882 }
4883
4884 wl1271_debug(DEBUG_PROBE,
4885 "PG Ver major = %d minor = %d, MAC %s present",
4886 major, minor, supported ? "is" : "is not");
4887
4888 return supported;
4889}
4890
4891static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
4892 u32 oui, u32 nic, int n)
4893{
4894 int i;
4895
4896 wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
4897 oui, nic, n);
4898
4899 if (nic + n - 1 > 0xffffff)
4900 wl1271_warning("NIC part of the MAC address wraps around!");
4901
4902 for (i = 0; i < n; i++) {
4903 wl->addresses[i].addr[0] = (u8)(oui >> 16);
4904 wl->addresses[i].addr[1] = (u8)(oui >> 8);
4905 wl->addresses[i].addr[2] = (u8) oui;
4906 wl->addresses[i].addr[3] = (u8)(nic >> 16);
4907 wl->addresses[i].addr[4] = (u8)(nic >> 8);
4908 wl->addresses[i].addr[5] = (u8) nic;
4909 nic++;
4910 }
4911
4912 wl->hw->wiphy->n_addresses = n;
4913 wl->hw->wiphy->addresses = wl->addresses;
4914}
4915
4916static void wl12xx_get_fuse_mac(struct wl1271 *wl)
4917{
4918 u32 mac1, mac2;
4919
4920 wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
4921
4922 mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
4923 mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
4924
4925 /* these are the two parts of the BD_ADDR */
4926 wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
4927 ((mac1 & 0xff000000) >> 24);
4928 wl->fuse_nic_addr = mac1 & 0xffffff;
4929
4930 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
4931}
4932
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004933static int wl12xx_get_hw_info(struct wl1271 *wl)
4934{
4935 int ret;
4936 u32 die_info;
4937
4938 ret = wl12xx_set_power_on(wl);
4939 if (ret < 0)
4940 goto out;
4941
4942 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
4943
4944 if (wl->chip.id == CHIP_ID_1283_PG20)
4945 die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
4946 else
4947 die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
4948
4949 wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
4950
Luciano Coelho5e037e72011-12-23 09:32:17 +02004951 if (!wl12xx_mac_in_fuse(wl)) {
4952 wl->fuse_oui_addr = 0;
4953 wl->fuse_nic_addr = 0;
4954 } else {
4955 wl12xx_get_fuse_mac(wl);
4956 }
4957
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004958 wl1271_power_off(wl);
4959out:
4960 return ret;
4961}
4962
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004963static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004964{
4965 int ret;
Luciano Coelho5e037e72011-12-23 09:32:17 +02004966 u32 oui_addr = 0, nic_addr = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004967
4968 if (wl->mac80211_registered)
4969 return 0;
4970
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004971 ret = wl12xx_get_hw_info(wl);
4972 if (ret < 0) {
4973 wl1271_error("couldn't get hw info");
4974 goto out;
4975 }
4976
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004977 ret = wl1271_fetch_nvs(wl);
4978 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004979 /* NOTE: The wl->nvs->nvs element must be first, in
4980 * order to simplify the casting, we assume it is at
4981 * the beginning of the wl->nvs structure.
4982 */
4983 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004984
Luciano Coelho5e037e72011-12-23 09:32:17 +02004985 oui_addr =
4986 (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
4987 nic_addr =
4988 (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004989 }
4990
Luciano Coelho5e037e72011-12-23 09:32:17 +02004991 /* if the MAC address is zeroed in the NVS derive from fuse */
4992 if (oui_addr == 0 && nic_addr == 0) {
4993 oui_addr = wl->fuse_oui_addr;
4994 /* fuse has the BD_ADDR, the WLAN addresses are the next two */
4995 nic_addr = wl->fuse_nic_addr + 1;
4996 }
4997
4998 wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004999
5000 ret = ieee80211_register_hw(wl->hw);
5001 if (ret < 0) {
5002 wl1271_error("unable to register mac80211 hw: %d", ret);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005003 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005004 }
5005
5006 wl->mac80211_registered = true;
5007
Eliad Pellerd60080a2010-11-24 12:53:16 +02005008 wl1271_debugfs_init(wl);
5009
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03005010 register_netdevice_notifier(&wl1271_dev_notifier);
5011
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005012 wl1271_notice("loaded");
5013
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005014out:
5015 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005016}
5017
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005018static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005019{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01005020 if (wl->state == WL1271_STATE_PLT)
Ido Yarivf3df1332012-01-11 09:42:39 +02005021 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01005022
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03005023 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005024 ieee80211_unregister_hw(wl->hw);
5025 wl->mac80211_registered = false;
5026
5027}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005028
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005029static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005030{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005031 static const u32 cipher_suites[] = {
5032 WLAN_CIPHER_SUITE_WEP40,
5033 WLAN_CIPHER_SUITE_WEP104,
5034 WLAN_CIPHER_SUITE_TKIP,
5035 WLAN_CIPHER_SUITE_CCMP,
5036 WL1271_CIPHER_SUITE_GEM,
5037 };
5038
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03005039 /* The tx descriptor buffer and the TKIP space. */
5040 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
5041 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005042
5043 /* unit us */
5044 /* FIXME: find a proper value */
5045 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03005046 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005047
5048 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02005049 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02005050 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02005051 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03005052 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03005053 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03005054 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03005055 IEEE80211_HW_AP_LINK_PS |
5056 IEEE80211_HW_AMPDU_AGGREGATION |
5057 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005058
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005059 wl->hw->wiphy->cipher_suites = cipher_suites;
5060 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
5061
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02005062 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03005063 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
5064 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005065 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03005066 wl->hw->wiphy->max_sched_scan_ssids = 16;
5067 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02005068 /*
5069 * Maximum length of elements in scanning probe request templates
5070 * should be the maximum length possible for a template, without
5071 * the IEEE80211 header of the template
5072 */
Eliad Peller154037d2011-08-14 13:17:12 +03005073 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02005074 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005075
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03005076 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
5077 sizeof(struct ieee80211_header);
5078
Eliad Peller1ec23f72011-08-25 14:26:54 +03005079 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
5080
Luciano Coelho4a31c112011-03-21 23:16:14 +02005081 /* make sure all our channels fit in the scanned_ch bitmask */
5082 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
5083 ARRAY_SIZE(wl1271_channels_5ghz) >
5084 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005085 /*
5086 * We keep local copies of the band structs because we need to
5087 * modify them on a per-device basis.
5088 */
5089 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
5090 sizeof(wl1271_band_2ghz));
5091 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
5092 sizeof(wl1271_band_5ghz));
5093
5094 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
5095 &wl->bands[IEEE80211_BAND_2GHZ];
5096 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
5097 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005098
Kalle Valo12bd8942010-03-18 12:26:33 +02005099 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02005100 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02005101
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01005102 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
5103
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02005104 /* the FW answers probe-requests in AP-mode */
5105 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
5106 wl->hw->wiphy->probe_resp_offload =
5107 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
5108 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
5109 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
5110
Felipe Balbia390e852011-10-06 10:07:44 +03005111 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005112
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005113 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02005114 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005115
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005116 wl->hw->max_rx_aggregation_subframes = 8;
5117
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005118 return 0;
5119}
5120
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005121#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005122
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005123static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005124{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005125 struct ieee80211_hw *hw;
5126 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005127 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005128 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005129
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005130 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005131
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005132 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5133 if (!hw) {
5134 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005135 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005136 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005137 }
5138
5139 wl = hw->priv;
5140 memset(wl, 0, sizeof(*wl));
5141
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005142 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005143 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005144
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005145 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005146
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005147 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005148 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005149 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5150
Ido Yariva6208652011-03-01 15:14:41 +02005151 skb_queue_head_init(&wl->deferred_rx_queue);
5152 skb_queue_head_init(&wl->deferred_tx_queue);
5153
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005154 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005155 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005156 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5157 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5158 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005159
Eliad Peller92ef8962011-06-07 12:50:46 +03005160 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5161 if (!wl->freezable_wq) {
5162 ret = -ENOMEM;
5163 goto err_hw;
5164 }
5165
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005166 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005167 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005168 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005169 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005170 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005171 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005172 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005173 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005174 wl->ap_ps_map = 0;
5175 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005176 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005177 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005178 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005179 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005180 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005181 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005182 wl->fwlog_size = 0;
5183 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005184
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005185 /* The system link is always allocated */
5186 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5187
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005188 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005189 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005190 wl->tx_frames[i] = NULL;
5191
5192 spin_lock_init(&wl->wl_lock);
5193
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005194 wl->state = WL1271_STATE_OFF;
5195 mutex_init(&wl->mutex);
5196
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005197 /* Apply default driver configuration. */
5198 wl1271_conf_init(wl);
5199
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005200 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5201 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5202 if (!wl->aggr_buf) {
5203 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005204 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005205 }
5206
Ido Yariv990f5de2011-03-31 10:06:59 +02005207 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5208 if (!wl->dummy_packet) {
5209 ret = -ENOMEM;
5210 goto err_aggr;
5211 }
5212
Ido Yariv95dac04f2011-06-06 14:57:06 +03005213 /* Allocate one page for the FW log */
5214 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5215 if (!wl->fwlog) {
5216 ret = -ENOMEM;
5217 goto err_dummy_packet;
5218 }
5219
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005220 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005221
Ido Yariv990f5de2011-03-31 10:06:59 +02005222err_dummy_packet:
5223 dev_kfree_skb(wl->dummy_packet);
5224
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005225err_aggr:
5226 free_pages((unsigned long)wl->aggr_buf, order);
5227
Eliad Peller92ef8962011-06-07 12:50:46 +03005228err_wq:
5229 destroy_workqueue(wl->freezable_wq);
5230
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005231err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005232 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005233 ieee80211_free_hw(hw);
5234
5235err_hw_alloc:
5236
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005237 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005238}
5239
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005240static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005241{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005242 /* Unblock any fwlog readers */
5243 mutex_lock(&wl->mutex);
5244 wl->fwlog_size = -1;
5245 wake_up_interruptible_all(&wl->fwlog_waitq);
5246 mutex_unlock(&wl->mutex);
5247
Felipe Balbif79f8902011-10-06 13:05:25 +03005248 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005249
Felipe Balbif79f8902011-10-06 13:05:25 +03005250 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005251
Felipe Balbif79f8902011-10-06 13:05:25 +03005252 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005253 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005254 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005255 free_pages((unsigned long)wl->aggr_buf,
5256 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005257
5258 wl1271_debugfs_exit(wl);
5259
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005260 vfree(wl->fw);
5261 wl->fw = NULL;
5262 kfree(wl->nvs);
5263 wl->nvs = NULL;
5264
5265 kfree(wl->fw_status);
5266 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005267 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005268
5269 ieee80211_free_hw(wl->hw);
5270
5271 return 0;
5272}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005273
Felipe Balbia390e852011-10-06 10:07:44 +03005274static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5275{
5276 struct wl1271 *wl = cookie;
5277 unsigned long flags;
5278
5279 wl1271_debug(DEBUG_IRQ, "IRQ");
5280
5281 /* complete the ELP completion */
5282 spin_lock_irqsave(&wl->wl_lock, flags);
5283 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5284 if (wl->elp_compl) {
5285 complete(wl->elp_compl);
5286 wl->elp_compl = NULL;
5287 }
5288
5289 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5290 /* don't enqueue a work right now. mark it as pending */
5291 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5292 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5293 disable_irq_nosync(wl->irq);
5294 pm_wakeup_event(wl->dev, 0);
5295 spin_unlock_irqrestore(&wl->wl_lock, flags);
5296 return IRQ_HANDLED;
5297 }
5298 spin_unlock_irqrestore(&wl->wl_lock, flags);
5299
5300 return IRQ_WAKE_THREAD;
5301}
5302
Felipe Balbice2a2172011-10-05 14:12:55 +03005303static int __devinit wl12xx_probe(struct platform_device *pdev)
5304{
Felipe Balbia390e852011-10-06 10:07:44 +03005305 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5306 struct ieee80211_hw *hw;
5307 struct wl1271 *wl;
5308 unsigned long irqflags;
5309 int ret = -ENODEV;
5310
5311 hw = wl1271_alloc_hw();
5312 if (IS_ERR(hw)) {
5313 wl1271_error("can't allocate hw");
5314 ret = PTR_ERR(hw);
5315 goto out;
5316 }
5317
5318 wl = hw->priv;
5319 wl->irq = platform_get_irq(pdev, 0);
5320 wl->ref_clock = pdata->board_ref_clock;
5321 wl->tcxo_clock = pdata->board_tcxo_clock;
5322 wl->platform_quirks = pdata->platform_quirks;
5323 wl->set_power = pdata->set_power;
5324 wl->dev = &pdev->dev;
5325 wl->if_ops = pdata->ops;
5326
5327 platform_set_drvdata(pdev, wl);
5328
5329 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5330 irqflags = IRQF_TRIGGER_RISING;
5331 else
5332 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5333
5334 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5335 irqflags,
5336 pdev->name, wl);
5337 if (ret < 0) {
5338 wl1271_error("request_irq() failed: %d", ret);
5339 goto out_free_hw;
5340 }
5341
5342 ret = enable_irq_wake(wl->irq);
5343 if (!ret) {
5344 wl->irq_wake_enabled = true;
5345 device_init_wakeup(wl->dev, 1);
5346 if (pdata->pwr_in_suspend)
5347 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5348
5349 }
5350 disable_irq(wl->irq);
5351
5352 ret = wl1271_init_ieee80211(wl);
5353 if (ret)
5354 goto out_irq;
5355
5356 ret = wl1271_register_hw(wl);
5357 if (ret)
5358 goto out_irq;
5359
Felipe Balbif79f8902011-10-06 13:05:25 +03005360 /* Create sysfs file to control bt coex state */
5361 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5362 if (ret < 0) {
5363 wl1271_error("failed to create sysfs file bt_coex_state");
5364 goto out_irq;
5365 }
5366
5367 /* Create sysfs file to get HW PG version */
5368 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5369 if (ret < 0) {
5370 wl1271_error("failed to create sysfs file hw_pg_ver");
5371 goto out_bt_coex_state;
5372 }
5373
5374 /* Create sysfs file for the FW log */
5375 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5376 if (ret < 0) {
5377 wl1271_error("failed to create sysfs file fwlog");
5378 goto out_hw_pg_ver;
5379 }
5380
Felipe Balbice2a2172011-10-05 14:12:55 +03005381 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005382
Felipe Balbif79f8902011-10-06 13:05:25 +03005383out_hw_pg_ver:
5384 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5385
5386out_bt_coex_state:
5387 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5388
Felipe Balbia390e852011-10-06 10:07:44 +03005389out_irq:
5390 free_irq(wl->irq, wl);
5391
5392out_free_hw:
5393 wl1271_free_hw(wl);
5394
5395out:
5396 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005397}
5398
5399static int __devexit wl12xx_remove(struct platform_device *pdev)
5400{
Felipe Balbia390e852011-10-06 10:07:44 +03005401 struct wl1271 *wl = platform_get_drvdata(pdev);
5402
5403 if (wl->irq_wake_enabled) {
5404 device_init_wakeup(wl->dev, 0);
5405 disable_irq_wake(wl->irq);
5406 }
5407 wl1271_unregister_hw(wl);
5408 free_irq(wl->irq, wl);
5409 wl1271_free_hw(wl);
5410
Felipe Balbice2a2172011-10-05 14:12:55 +03005411 return 0;
5412}
5413
5414static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005415 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005416 { } /* Terminating Entry */
5417};
5418MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5419
5420static struct platform_driver wl12xx_driver = {
5421 .probe = wl12xx_probe,
5422 .remove = __devexit_p(wl12xx_remove),
5423 .id_table = wl12xx_id_table,
5424 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005425 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005426 .owner = THIS_MODULE,
5427 }
5428};
5429
5430static int __init wl12xx_init(void)
5431{
5432 return platform_driver_register(&wl12xx_driver);
5433}
5434module_init(wl12xx_init);
5435
5436static void __exit wl12xx_exit(void)
5437{
5438 platform_driver_unregister(&wl12xx_driver);
5439}
5440module_exit(wl12xx_exit);
5441
Guy Eilam491bbd62011-01-12 10:33:29 +01005442u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005443EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005444module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005445MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5446
Ido Yariv95dac04f2011-06-06 14:57:06 +03005447module_param_named(fwlog, fwlog_param, charp, 0);
Luciano Coelho2c882fa2012-02-07 12:37:33 +02005448MODULE_PARM_DESC(fwlog,
Ido Yariv95dac04f2011-06-06 14:57:06 +03005449 "FW logger options: continuous, ondemand, dbgpins or disable");
5450
Eliad Peller2a5bff02011-08-25 18:10:59 +03005451module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5452MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5453
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005454MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005455MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005456MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");