blob: f8748cedbae19bfb4753ec579cec9c9040030fdf [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
1235static int wl1271_chip_wakeup(struct wl1271 *wl)
1236{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001237 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001238 int ret = 0;
1239
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001240 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001241 ret = wl1271_power_on(wl);
1242 if (ret < 0)
1243 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001244 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001245 wl1271_io_reset(wl);
1246 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247
1248 /* We don't need a real memory partition here, because we only want
1249 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001250 memset(&partition, 0, sizeof(partition));
1251 partition.reg.start = REGISTERS_BASE;
1252 partition.reg.size = REGISTERS_DOWN_SIZE;
1253 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254
1255 /* ELP module wake up */
1256 wl1271_fw_wakeup(wl);
1257
1258 /* whal_FwCtrl_BootSm() */
1259
1260 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001261 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001262
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001263 /*
1264 * For wl127x based devices we could use the default block
1265 * size (512 bytes), but due to a bug in the sdio driver, we
1266 * need to set it explicitly after the chip is powered on. To
1267 * simplify the code and since the performance impact is
1268 * negligible, we use the same block size for all different
1269 * chip types.
1270 */
1271 if (!wl1271_set_block_size(wl))
1272 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273
1274 switch (wl->chip.id) {
1275 case CHIP_ID_1271_PG10:
1276 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1277 wl->chip.id);
1278
1279 ret = wl1271_setup(wl);
1280 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001281 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001282 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001284
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 case CHIP_ID_1271_PG20:
1286 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1287 wl->chip.id);
1288
1289 ret = wl1271_setup(wl);
1290 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001291 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001292 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001293 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001294
Shahar Levi0830cee2011-03-06 16:32:20 +02001295 case CHIP_ID_1283_PG20:
1296 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1297 wl->chip.id);
1298
1299 ret = wl1271_setup(wl);
1300 if (ret < 0)
1301 goto out;
1302 break;
1303 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001304 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001305 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001307 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001308 }
1309
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001310 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001311 ret = wl1271_fetch_firmware(wl);
1312 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001313 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314 }
1315
1316 /* No NVS from netlink, try to get it from the filesystem */
1317 if (wl->nvs == NULL) {
1318 ret = wl1271_fetch_nvs(wl);
1319 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001320 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321 }
1322
1323out:
1324 return ret;
1325}
1326
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327int wl1271_plt_start(struct wl1271 *wl)
1328{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001329 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001330 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331 int ret;
1332
1333 mutex_lock(&wl->mutex);
1334
1335 wl1271_notice("power up");
1336
1337 if (wl->state != WL1271_STATE_OFF) {
1338 wl1271_error("cannot go into PLT state because not "
1339 "in off state: %d", wl->state);
1340 ret = -EBUSY;
1341 goto out;
1342 }
1343
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001344 while (retries) {
1345 retries--;
1346 ret = wl1271_chip_wakeup(wl);
1347 if (ret < 0)
1348 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001349
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001350 ret = wl1271_boot(wl);
1351 if (ret < 0)
1352 goto power_off;
1353
1354 ret = wl1271_plt_init(wl);
1355 if (ret < 0)
1356 goto irq_disable;
1357
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001358 wl->state = WL1271_STATE_PLT;
1359 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001360 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001361
Gery Kahn6f07b722011-07-18 14:21:49 +03001362 /* update hw/fw version info in wiphy struct */
1363 wiphy->hw_version = wl->chip.id;
1364 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1365 sizeof(wiphy->fw_version));
1366
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367 goto out;
1368
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001369irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001370 mutex_unlock(&wl->mutex);
1371 /* Unlocking the mutex in the middle of handling is
1372 inherently unsafe. In this case we deem it safe to do,
1373 because we need to let any possibly pending IRQ out of
1374 the system (and while we are WL1271_STATE_OFF the IRQ
1375 work function will not do anything.) Also, any other
1376 possible concurrent operations will fail due to the
1377 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001378 wl1271_disable_interrupts(wl);
1379 wl1271_flush_deferred_work(wl);
1380 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001381 mutex_lock(&wl->mutex);
1382power_off:
1383 wl1271_power_off(wl);
1384 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001386 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1387 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001388out:
1389 mutex_unlock(&wl->mutex);
1390
1391 return ret;
1392}
1393
Luciano Coelho4623ec72011-03-21 19:26:41 +02001394static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001395{
1396 int ret = 0;
1397
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001398 wl1271_notice("power down");
1399
1400 if (wl->state != WL1271_STATE_PLT) {
1401 wl1271_error("cannot power down because not in PLT "
1402 "state: %d", wl->state);
1403 ret = -EBUSY;
1404 goto out;
1405 }
1406
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407 wl1271_power_off(wl);
1408
1409 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001410 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001411
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001412 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001413 wl1271_disable_interrupts(wl);
1414 wl1271_flush_deferred_work(wl);
1415 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001416 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001417 mutex_lock(&wl->mutex);
1418out:
1419 return ret;
1420}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001421
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001422int wl1271_plt_stop(struct wl1271 *wl)
1423{
1424 int ret;
1425
1426 mutex_lock(&wl->mutex);
1427 ret = __wl1271_plt_stop(wl);
1428 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429 return ret;
1430}
1431
Johannes Berg7bb45682011-02-24 14:42:06 +01001432static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001433{
1434 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001435 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1436 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001437 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001438 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001439 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001440 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441
Eliad Peller0f168012011-10-11 13:52:25 +02001442 if (vif)
1443 wlvif = wl12xx_vif_to_data(vif);
1444
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001445 mapping = skb_get_queue_mapping(skb);
1446 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001447
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001448 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001449
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001450 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001451
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001452 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001453 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001454 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001455 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001456 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001457 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001458 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001459
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001460 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1461 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1462
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001463 wl->tx_queue_count[q]++;
1464
1465 /*
1466 * The workqueue is slow to process the tx_queue and we need stop
1467 * the queue here, otherwise the queue will get too long.
1468 */
1469 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1470 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1471 ieee80211_stop_queue(wl->hw, mapping);
1472 set_bit(q, &wl->stopped_queues_map);
1473 }
1474
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001475 /*
1476 * The chip specific setup must run before the first TX packet -
1477 * before that, the tx_work will not be initialized!
1478 */
1479
Ido Yarivb07d4032011-03-01 15:14:43 +02001480 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1481 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001482 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001483
Arik Nemtsov04216da2011-08-14 13:17:38 +03001484out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001485 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486}
1487
Shahar Leviae47c452011-03-06 16:32:14 +02001488int wl1271_tx_dummy_packet(struct wl1271 *wl)
1489{
Ido Yariv990f5de2011-03-31 10:06:59 +02001490 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001491 int q;
1492
1493 /* no need to queue a new dummy packet if one is already pending */
1494 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1495 return 0;
1496
1497 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001498
Ido Yariv990f5de2011-03-31 10:06:59 +02001499 spin_lock_irqsave(&wl->wl_lock, flags);
1500 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001501 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001502 spin_unlock_irqrestore(&wl->wl_lock, flags);
1503
1504 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1505 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001506 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001507
1508 /*
1509 * If the FW TX is busy, TX work will be scheduled by the threaded
1510 * interrupt handler function
1511 */
1512 return 0;
1513}
1514
1515/*
1516 * The size of the dummy packet should be at least 1400 bytes. However, in
1517 * order to minimize the number of bus transactions, aligning it to 512 bytes
1518 * boundaries could be beneficial, performance wise
1519 */
1520#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1521
Luciano Coelhocf27d862011-04-01 21:08:23 +03001522static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001523{
1524 struct sk_buff *skb;
1525 struct ieee80211_hdr_3addr *hdr;
1526 unsigned int dummy_packet_size;
1527
1528 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1529 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1530
1531 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001532 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001533 wl1271_warning("Failed to allocate a dummy packet skb");
1534 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001535 }
1536
1537 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1538
1539 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1540 memset(hdr, 0, sizeof(*hdr));
1541 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001542 IEEE80211_STYPE_NULLFUNC |
1543 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001544
Ido Yariv990f5de2011-03-31 10:06:59 +02001545 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001546
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001547 /* Dummy packets require the TID to be management */
1548 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001549
1550 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001551 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001552 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001553
Ido Yariv990f5de2011-03-31 10:06:59 +02001554 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001555}
1556
Ido Yariv990f5de2011-03-31 10:06:59 +02001557
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001558static struct notifier_block wl1271_dev_notifier = {
1559 .notifier_call = wl1271_dev_notify,
1560};
1561
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001562#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001563static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1564 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001565{
Eliad Pellere85d1622011-06-27 13:06:43 +03001566 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001567
Eliad Peller94390642011-05-13 11:57:13 +03001568 mutex_lock(&wl->mutex);
1569
Eliad Pellerba8447f2011-10-10 10:13:00 +02001570 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001571 goto out_unlock;
1572
Eliad Peller94390642011-05-13 11:57:13 +03001573 ret = wl1271_ps_elp_wakeup(wl);
1574 if (ret < 0)
1575 goto out_unlock;
1576
1577 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001578 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001579 DECLARE_COMPLETION_ONSTACK(compl);
1580
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001581 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001582 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001583 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001584 if (ret < 0)
1585 goto out_sleep;
1586
1587 /* we must unlock here so we will be able to get events */
1588 wl1271_ps_elp_sleep(wl);
1589 mutex_unlock(&wl->mutex);
1590
1591 ret = wait_for_completion_timeout(
1592 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
Pontus Fuchsef187062011-12-14 14:32:23 +01001593
1594 mutex_lock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001595 if (ret <= 0) {
1596 wl1271_warning("couldn't enter ps mode!");
1597 ret = -EBUSY;
Pontus Fuchsef187062011-12-14 14:32:23 +01001598 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001599 }
1600
Eliad Peller94390642011-05-13 11:57:13 +03001601 ret = wl1271_ps_elp_wakeup(wl);
1602 if (ret < 0)
Pontus Fuchsef187062011-12-14 14:32:23 +01001603 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001604 }
1605out_sleep:
1606 wl1271_ps_elp_sleep(wl);
Pontus Fuchsef187062011-12-14 14:32:23 +01001607out_cleanup:
1608 wlvif->ps_compl = NULL;
Eliad Peller94390642011-05-13 11:57:13 +03001609out_unlock:
1610 mutex_unlock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001611 return ret;
1612
1613}
1614
Eliad Peller0603d892011-10-05 11:55:51 +02001615static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1616 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001617{
Eliad Pellere85d1622011-06-27 13:06:43 +03001618 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001619
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001620 mutex_lock(&wl->mutex);
1621
Eliad Peller53d40d02011-10-10 10:13:02 +02001622 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001623 goto out_unlock;
1624
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001625 ret = wl1271_ps_elp_wakeup(wl);
1626 if (ret < 0)
1627 goto out_unlock;
1628
Eliad Peller0603d892011-10-05 11:55:51 +02001629 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001630
1631 wl1271_ps_elp_sleep(wl);
1632out_unlock:
1633 mutex_unlock(&wl->mutex);
1634 return ret;
1635
1636}
1637
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001638static int wl1271_configure_suspend(struct wl1271 *wl,
1639 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001640{
Eliad Peller536129c2011-10-05 11:55:45 +02001641 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001642 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001643 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001644 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001645 return 0;
1646}
1647
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001648static void wl1271_configure_resume(struct wl1271 *wl,
1649 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001650{
1651 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001652 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1653 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001654
1655 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001656 return;
1657
1658 mutex_lock(&wl->mutex);
1659 ret = wl1271_ps_elp_wakeup(wl);
1660 if (ret < 0)
1661 goto out;
1662
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001663 if (is_sta) {
1664 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001665 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001666 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001667 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001668 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001669 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001670 }
Eliad Peller94390642011-05-13 11:57:13 +03001671
1672 wl1271_ps_elp_sleep(wl);
1673out:
1674 mutex_unlock(&wl->mutex);
1675}
1676
Eliad Peller402e48612011-05-13 11:57:09 +03001677static int wl1271_op_suspend(struct ieee80211_hw *hw,
1678 struct cfg80211_wowlan *wow)
1679{
1680 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001681 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001682 int ret;
1683
Eliad Peller402e48612011-05-13 11:57:09 +03001684 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001685 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001686
Eliad Peller4a859df2011-06-06 12:21:52 +03001687 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001688 wl12xx_for_each_wlvif(wl, wlvif) {
1689 ret = wl1271_configure_suspend(wl, wlvif);
1690 if (ret < 0) {
1691 wl1271_warning("couldn't prepare device to suspend");
1692 return ret;
1693 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001694 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001695 /* flush any remaining work */
1696 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001697
1698 /*
1699 * disable and re-enable interrupts in order to flush
1700 * the threaded_irq
1701 */
1702 wl1271_disable_interrupts(wl);
1703
1704 /*
1705 * set suspended flag to avoid triggering a new threaded_irq
1706 * work. no need for spinlock as interrupts are disabled.
1707 */
1708 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1709
1710 wl1271_enable_interrupts(wl);
1711 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001712 wl12xx_for_each_wlvif(wl, wlvif) {
1713 flush_delayed_work(&wlvif->pspoll_work);
1714 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001715 flush_delayed_work(&wl->elp_work);
1716
Eliad Peller402e48612011-05-13 11:57:09 +03001717 return 0;
1718}
1719
1720static int wl1271_op_resume(struct ieee80211_hw *hw)
1721{
1722 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001723 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001724 unsigned long flags;
1725 bool run_irq_work = false;
1726
Eliad Peller402e48612011-05-13 11:57:09 +03001727 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1728 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001729 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001730
1731 /*
1732 * re-enable irq_work enqueuing, and call irq_work directly if
1733 * there is a pending work.
1734 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001735 spin_lock_irqsave(&wl->wl_lock, flags);
1736 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1737 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1738 run_irq_work = true;
1739 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001740
Eliad Peller4a859df2011-06-06 12:21:52 +03001741 if (run_irq_work) {
1742 wl1271_debug(DEBUG_MAC80211,
1743 "run postponed irq_work directly");
1744 wl1271_irq(0, wl);
1745 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001746 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001747 wl12xx_for_each_wlvif(wl, wlvif) {
1748 wl1271_configure_resume(wl, wlvif);
1749 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001750 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001751
Eliad Peller402e48612011-05-13 11:57:09 +03001752 return 0;
1753}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001754#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001755
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001756static int wl1271_op_start(struct ieee80211_hw *hw)
1757{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001758 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1759
1760 /*
1761 * We have to delay the booting of the hardware because
1762 * we need to know the local MAC address before downloading and
1763 * initializing the firmware. The MAC address cannot be changed
1764 * after boot, and without the proper MAC address, the firmware
1765 * will not function properly.
1766 *
1767 * The MAC address is first known when the corresponding interface
1768 * is added. That is where we will initialize the hardware.
1769 */
1770
1771 return 0;
1772}
1773
1774static void wl1271_op_stop(struct ieee80211_hw *hw)
1775{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001776 struct wl1271 *wl = hw->priv;
1777 int i;
1778
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001779 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001780
Eliad Peller10c8cd02011-10-10 10:13:06 +02001781 mutex_lock(&wl->mutex);
1782 if (wl->state == WL1271_STATE_OFF) {
1783 mutex_unlock(&wl->mutex);
1784 return;
1785 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001786 /*
1787 * this must be before the cancel_work calls below, so that the work
1788 * functions don't perform further work.
1789 */
1790 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001791 mutex_unlock(&wl->mutex);
1792
1793 mutex_lock(&wl_list_mutex);
1794 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001795 mutex_unlock(&wl_list_mutex);
1796
1797 wl1271_disable_interrupts(wl);
1798 wl1271_flush_deferred_work(wl);
1799 cancel_delayed_work_sync(&wl->scan_complete_work);
1800 cancel_work_sync(&wl->netstack_work);
1801 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001802 cancel_delayed_work_sync(&wl->elp_work);
1803
1804 /* let's notify MAC80211 about the remaining pending TX frames */
1805 wl12xx_tx_reset(wl, true);
1806 mutex_lock(&wl->mutex);
1807
1808 wl1271_power_off(wl);
1809
1810 wl->band = IEEE80211_BAND_2GHZ;
1811
1812 wl->rx_counter = 0;
1813 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1814 wl->tx_blocks_available = 0;
1815 wl->tx_allocated_blocks = 0;
1816 wl->tx_results_count = 0;
1817 wl->tx_packets_count = 0;
1818 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001819 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1820 wl->ap_fw_ps_map = 0;
1821 wl->ap_ps_map = 0;
1822 wl->sched_scanning = false;
1823 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1824 memset(wl->links_map, 0, sizeof(wl->links_map));
1825 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1826 wl->active_sta_count = 0;
1827
1828 /* The system link is always allocated */
1829 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1830
1831 /*
1832 * this is performed after the cancel_work calls and the associated
1833 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1834 * get executed before all these vars have been reset.
1835 */
1836 wl->flags = 0;
1837
1838 wl->tx_blocks_freed = 0;
1839
1840 for (i = 0; i < NUM_TX_QUEUES; i++) {
1841 wl->tx_pkts_freed[i] = 0;
1842 wl->tx_allocated_pkts[i] = 0;
1843 }
1844
1845 wl1271_debugfs_reset(wl);
1846
1847 kfree(wl->fw_status);
1848 wl->fw_status = NULL;
1849 kfree(wl->tx_res_if);
1850 wl->tx_res_if = NULL;
1851 kfree(wl->target_mem_map);
1852 wl->target_mem_map = NULL;
1853
1854 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001855}
1856
Eliad Pellere5a359f2011-10-10 10:13:15 +02001857static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1858{
1859 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1860 WL12XX_MAX_RATE_POLICIES);
1861 if (policy >= WL12XX_MAX_RATE_POLICIES)
1862 return -EBUSY;
1863
1864 __set_bit(policy, wl->rate_policies_map);
1865 *idx = policy;
1866 return 0;
1867}
1868
1869static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1870{
1871 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1872 return;
1873
1874 __clear_bit(*idx, wl->rate_policies_map);
1875 *idx = WL12XX_MAX_RATE_POLICIES;
1876}
1877
Eliad Peller536129c2011-10-05 11:55:45 +02001878static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001879{
Eliad Peller536129c2011-10-05 11:55:45 +02001880 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001881 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001882 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001883 return WL1271_ROLE_P2P_GO;
1884 else
1885 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001886
1887 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001888 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001889 return WL1271_ROLE_P2P_CL;
1890 else
1891 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001892
Eliad Peller227e81e2011-08-14 13:17:26 +03001893 case BSS_TYPE_IBSS:
1894 return WL1271_ROLE_IBSS;
1895
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001896 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001897 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001898 }
1899 return WL12XX_INVALID_ROLE_TYPE;
1900}
1901
Eliad Peller83587502011-10-10 10:12:53 +02001902static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001903{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001904 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001905 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001906
Eliad Peller48e93e42011-10-10 10:12:58 +02001907 /* clear everything but the persistent data */
1908 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001909
1910 switch (ieee80211_vif_type_p2p(vif)) {
1911 case NL80211_IFTYPE_P2P_CLIENT:
1912 wlvif->p2p = 1;
1913 /* fall-through */
1914 case NL80211_IFTYPE_STATION:
1915 wlvif->bss_type = BSS_TYPE_STA_BSS;
1916 break;
1917 case NL80211_IFTYPE_ADHOC:
1918 wlvif->bss_type = BSS_TYPE_IBSS;
1919 break;
1920 case NL80211_IFTYPE_P2P_GO:
1921 wlvif->p2p = 1;
1922 /* fall-through */
1923 case NL80211_IFTYPE_AP:
1924 wlvif->bss_type = BSS_TYPE_AP_BSS;
1925 break;
1926 default:
1927 wlvif->bss_type = MAX_BSS_TYPE;
1928 return -EOPNOTSUPP;
1929 }
1930
Eliad Peller0603d892011-10-05 11:55:51 +02001931 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001932 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001933 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001934
Eliad Pellere936bbe2011-10-05 11:55:56 +02001935 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1936 wlvif->bss_type == BSS_TYPE_IBSS) {
1937 /* init sta/ibss data */
1938 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001939 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1940 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1941 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001942 } else {
1943 /* init ap data */
1944 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1945 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001946 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1947 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1948 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1949 wl12xx_allocate_rate_policy(wl,
1950 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001951 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001952
Eliad Peller83587502011-10-10 10:12:53 +02001953 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1954 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001955 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001956 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001957 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001958 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1959
Eliad Peller1b92f152011-10-10 10:13:09 +02001960 /*
1961 * mac80211 configures some values globally, while we treat them
1962 * per-interface. thus, on init, we have to copy them from wl
1963 */
1964 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001965 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001966 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02001967
Eliad Peller9eb599e2011-10-10 10:12:59 +02001968 INIT_WORK(&wlvif->rx_streaming_enable_work,
1969 wl1271_rx_streaming_enable_work);
1970 INIT_WORK(&wlvif->rx_streaming_disable_work,
1971 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02001972 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02001973 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001974
Eliad Peller9eb599e2011-10-10 10:12:59 +02001975 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1976 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001977 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001978}
1979
Eliad Peller1d095472011-10-10 10:12:49 +02001980static bool wl12xx_init_fw(struct wl1271 *wl)
1981{
1982 int retries = WL1271_BOOT_RETRIES;
1983 bool booted = false;
1984 struct wiphy *wiphy = wl->hw->wiphy;
1985 int ret;
1986
1987 while (retries) {
1988 retries--;
1989 ret = wl1271_chip_wakeup(wl);
1990 if (ret < 0)
1991 goto power_off;
1992
1993 ret = wl1271_boot(wl);
1994 if (ret < 0)
1995 goto power_off;
1996
1997 ret = wl1271_hw_init(wl);
1998 if (ret < 0)
1999 goto irq_disable;
2000
2001 booted = true;
2002 break;
2003
2004irq_disable:
2005 mutex_unlock(&wl->mutex);
2006 /* Unlocking the mutex in the middle of handling is
2007 inherently unsafe. In this case we deem it safe to do,
2008 because we need to let any possibly pending IRQ out of
2009 the system (and while we are WL1271_STATE_OFF the IRQ
2010 work function will not do anything.) Also, any other
2011 possible concurrent operations will fail due to the
2012 current state, hence the wl1271 struct should be safe. */
2013 wl1271_disable_interrupts(wl);
2014 wl1271_flush_deferred_work(wl);
2015 cancel_work_sync(&wl->netstack_work);
2016 mutex_lock(&wl->mutex);
2017power_off:
2018 wl1271_power_off(wl);
2019 }
2020
2021 if (!booted) {
2022 wl1271_error("firmware boot failed despite %d retries",
2023 WL1271_BOOT_RETRIES);
2024 goto out;
2025 }
2026
2027 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2028
2029 /* update hw/fw version info in wiphy struct */
2030 wiphy->hw_version = wl->chip.id;
2031 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2032 sizeof(wiphy->fw_version));
2033
2034 /*
2035 * Now we know if 11a is supported (info from the NVS), so disable
2036 * 11a channels if not supported
2037 */
2038 if (!wl->enable_11a)
2039 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2040
2041 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2042 wl->enable_11a ? "" : "not ");
2043
2044 wl->state = WL1271_STATE_ON;
2045out:
2046 return booted;
2047}
2048
Eliad Peller92e712d2011-12-18 20:25:43 +02002049static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2050{
2051 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2052}
2053
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002054static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2055 struct ieee80211_vif *vif)
2056{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002057 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002058 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002059 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002060 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002061 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002062
Johannes Bergea086352012-01-19 09:29:58 +01002063 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2064 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002065
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002066 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002067 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002068
2069 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002070 ret = wl1271_ps_elp_wakeup(wl);
2071 if (ret < 0)
2072 goto out_unlock;
2073
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002074 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002075 wl1271_debug(DEBUG_MAC80211,
2076 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002077 ret = -EBUSY;
2078 goto out;
2079 }
2080
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002081 /*
2082 * in some very corner case HW recovery scenarios its possible to
2083 * get here before __wl1271_op_remove_interface is complete, so
2084 * opt out if that is the case.
2085 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002086 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2087 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002088 ret = -EBUSY;
2089 goto out;
2090 }
2091
Eliad Peller83587502011-10-10 10:12:53 +02002092 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002093 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002094 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002095
Eliad Peller252efa42011-10-05 11:56:00 +02002096 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002097 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002098 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2099 ret = -EINVAL;
2100 goto out;
2101 }
Eliad Peller1d095472011-10-10 10:12:49 +02002102
Eliad Peller784f6942011-10-05 11:55:39 +02002103 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002104 * TODO: after the nvs issue will be solved, move this block
2105 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002106 */
Eliad Peller1d095472011-10-10 10:12:49 +02002107 if (wl->state == WL1271_STATE_OFF) {
2108 /*
2109 * we still need this in order to configure the fw
2110 * while uploading the nvs
2111 */
2112 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002113
Eliad Peller1d095472011-10-10 10:12:49 +02002114 booted = wl12xx_init_fw(wl);
2115 if (!booted) {
2116 ret = -EINVAL;
2117 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002118 }
Eliad Peller1d095472011-10-10 10:12:49 +02002119 }
Eliad Peller04e80792011-08-14 13:17:09 +03002120
Eliad Peller1d095472011-10-10 10:12:49 +02002121 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2122 wlvif->bss_type == BSS_TYPE_IBSS) {
2123 /*
2124 * The device role is a special role used for
2125 * rx and tx frames prior to association (as
2126 * the STA role can get packets only from
2127 * its associated bssid)
2128 */
Eliad Peller784f6942011-10-05 11:55:39 +02002129 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002130 WL1271_ROLE_DEVICE,
2131 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002132 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002133 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002134 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002135
Eliad Peller1d095472011-10-10 10:12:49 +02002136 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2137 role_type, &wlvif->role_id);
2138 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002139 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002140
2141 ret = wl1271_init_vif_specific(wl, vif);
2142 if (ret < 0)
2143 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002144
2145 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002146 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002147 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002148
2149 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2150 wl->ap_count++;
2151 else
2152 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002153out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002154 wl1271_ps_elp_sleep(wl);
2155out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002156 mutex_unlock(&wl->mutex);
2157
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002158 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002159 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002160 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002161 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002162
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002163 return ret;
2164}
2165
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002166static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002167 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002168 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002169{
Eliad Peller536129c2011-10-05 11:55:45 +02002170 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002171 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002172
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002173 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002174
Eliad Peller10c8cd02011-10-10 10:13:06 +02002175 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2176 return;
2177
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002178 wl->vif = NULL;
2179
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002180 /* because of hardware recovery, we may get here twice */
2181 if (wl->state != WL1271_STATE_ON)
2182 return;
2183
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002184 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002185
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002186 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002187 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002188 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002189
Eliad Pellerbaf62772011-10-10 10:12:52 +02002190 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2191 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002192 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002193 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002194 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002195 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002196 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002197 }
2198
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002199 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2200 /* disable active roles */
2201 ret = wl1271_ps_elp_wakeup(wl);
2202 if (ret < 0)
2203 goto deinit;
2204
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002205 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2206 wlvif->bss_type == BSS_TYPE_IBSS) {
2207 if (wl12xx_dev_role_started(wlvif))
2208 wl12xx_stop_dev(wl, wlvif);
2209
Eliad Peller7edebf52011-10-05 11:55:52 +02002210 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002211 if (ret < 0)
2212 goto deinit;
2213 }
2214
Eliad Peller0603d892011-10-05 11:55:51 +02002215 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002216 if (ret < 0)
2217 goto deinit;
2218
2219 wl1271_ps_elp_sleep(wl);
2220 }
2221deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002222 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002223 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002224
2225 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2226 wlvif->bss_type == BSS_TYPE_IBSS) {
2227 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2228 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2229 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2230 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2231 } else {
2232 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2233 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2234 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2235 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2236 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2237 wl12xx_free_rate_policy(wl,
2238 &wlvif->ap.ucast_rate_idx[i]);
2239 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002240
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002241 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002242 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002243 if (wl->last_wlvif == wlvif)
2244 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002245 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002246 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002247 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002248 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002249
Eliad Pellera4e41302011-10-11 11:49:15 +02002250 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2251 wl->ap_count--;
2252 else
2253 wl->sta_count--;
2254
Eliad Pellerbaf62772011-10-10 10:12:52 +02002255 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002256 del_timer_sync(&wlvif->rx_streaming_timer);
2257 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2258 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002259 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002260
Eliad Pellerbaf62772011-10-10 10:12:52 +02002261 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002262}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002263
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002264static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2265 struct ieee80211_vif *vif)
2266{
2267 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002268 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002269 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002270
2271 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002272
2273 if (wl->state == WL1271_STATE_OFF ||
2274 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2275 goto out;
2276
Juuso Oikarinen67353292010-11-18 15:19:02 +02002277 /*
2278 * wl->vif can be null here if someone shuts down the interface
2279 * just when hardware recovery has been started.
2280 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002281 wl12xx_for_each_wlvif(wl, iter) {
2282 if (iter != wlvif)
2283 continue;
2284
Eliad Peller536129c2011-10-05 11:55:45 +02002285 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002286 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002287 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002288 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002289out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002290 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002291 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002292}
2293
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002294static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2295 struct ieee80211_vif *vif,
2296 enum nl80211_iftype new_type, bool p2p)
2297{
2298 wl1271_op_remove_interface(hw, vif);
2299
2300 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2301 vif->p2p = p2p;
2302 return wl1271_op_add_interface(hw, vif);
2303}
2304
Eliad Peller87fbcb02011-10-05 11:55:41 +02002305static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2306 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002307{
2308 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002309 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002310
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002311 /*
2312 * One of the side effects of the JOIN command is that is clears
2313 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2314 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002315 * Currently the only valid scenario for JOIN during association
2316 * is on roaming, in which case we will also be given new keys.
2317 * Keep the below message for now, unless it starts bothering
2318 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002319 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002320 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002321 wl1271_info("JOIN while associated.");
2322
2323 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002324 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002325
Eliad Peller227e81e2011-08-14 13:17:26 +03002326 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002327 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002328 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002329 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002330 if (ret < 0)
2331 goto out;
2332
Eliad Pellerba8447f2011-10-10 10:13:00 +02002333 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002334 goto out;
2335
2336 /*
2337 * The join command disable the keep-alive mode, shut down its process,
2338 * and also clear the template config, so we need to reset it all after
2339 * the join. The acx_aid starts the keep-alive process, and the order
2340 * of the commands below is relevant.
2341 */
Eliad Peller0603d892011-10-05 11:55:51 +02002342 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002343 if (ret < 0)
2344 goto out;
2345
Eliad Peller0603d892011-10-05 11:55:51 +02002346 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002347 if (ret < 0)
2348 goto out;
2349
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002350 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002351 if (ret < 0)
2352 goto out;
2353
Eliad Peller0603d892011-10-05 11:55:51 +02002354 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2355 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002356 ACX_KEEP_ALIVE_TPL_VALID);
2357 if (ret < 0)
2358 goto out;
2359
2360out:
2361 return ret;
2362}
2363
Eliad Peller0603d892011-10-05 11:55:51 +02002364static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002365{
2366 int ret;
2367
Eliad Peller52630c52011-10-10 10:13:08 +02002368 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002369 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2370
Shahar Levi6d158ff2011-09-08 13:01:33 +03002371 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002372 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002373 }
2374
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002375 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002376 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002377 if (ret < 0)
2378 goto out;
2379
Oz Krakowskib992c682011-06-26 10:36:02 +03002380 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002381 wlvif->tx_security_last_seq_lsb = 0;
2382 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002383
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002384out:
2385 return ret;
2386}
2387
Eliad Peller87fbcb02011-10-05 11:55:41 +02002388static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002389{
Eliad Peller1b92f152011-10-10 10:13:09 +02002390 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002391 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002392}
2393
Eliad Peller87fbcb02011-10-05 11:55:41 +02002394static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2395 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002396{
2397 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002398 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2399
2400 if (idle == cur_idle)
2401 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002402
2403 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002404 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002405 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002406 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002407 if (ret < 0)
2408 goto out;
2409 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002410 wlvif->rate_set =
2411 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2412 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002413 if (ret < 0)
2414 goto out;
2415 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002416 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002417 ACX_KEEP_ALIVE_TPL_INVALID);
2418 if (ret < 0)
2419 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002420 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002421 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002422 /* The current firmware only supports sched_scan in idle */
2423 if (wl->sched_scanning) {
2424 wl1271_scan_sched_scan_stop(wl);
2425 ieee80211_sched_scan_stopped(wl->hw);
2426 }
2427
Eliad Peller679a6732011-10-11 11:55:44 +02002428 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002429 if (ret < 0)
2430 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002431 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002432 }
2433
2434out:
2435 return ret;
2436}
2437
Eliad Peller9f259c42011-10-10 10:13:12 +02002438static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2439 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002440{
Eliad Peller9f259c42011-10-10 10:13:12 +02002441 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2442 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002443
2444 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2445
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002446 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002447 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002448 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002449 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002450 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002451 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002452 wlvif->band = conf->channel->band;
2453 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002454
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002455 if (!is_ap) {
2456 /*
2457 * FIXME: the mac80211 should really provide a fixed
2458 * rate to use here. for now, just use the smallest
2459 * possible rate for the band as a fixed rate for
2460 * association frames and other control messages.
2461 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002462 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002463 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002464
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002465 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002466 wl1271_tx_min_rate_get(wl,
2467 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002468 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002469 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002470 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002471 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002472
Eliad Pellerba8447f2011-10-10 10:13:00 +02002473 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2474 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002475 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002476 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002477 ret = wl12xx_croc(wl,
2478 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002479 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002480 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002481 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002482 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002483 if (ret < 0)
2484 wl1271_warning("cmd join on channel "
2485 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002486 } else {
2487 /*
2488 * change the ROC channel. do it only if we are
2489 * not idle. otherwise, CROC will be called
2490 * anyway.
2491 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002492 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002493 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002494 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002495 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002496 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002497
Eliad Peller679a6732011-10-11 11:55:44 +02002498 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002499 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002500 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002501 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002502 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002503 }
2504 }
2505
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002506 /*
2507 * if mac80211 changes the PSM mode, make sure the mode is not
2508 * incorrectly changed after the pspoll failure active window.
2509 */
2510 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002511 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002512
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002513 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002514 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2515 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002516
2517 /*
2518 * We enter PSM only if we're already associated.
2519 * If we're not, we'll enter it when joining an SSID,
2520 * through the bss_info_changed() hook.
2521 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002522 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002523 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002524 ret = wl1271_ps_set_mode(wl, wlvif,
2525 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002526 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002527 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002528 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002529 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002530 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002531
Eliad Pellerc29bb002011-10-10 10:13:03 +02002532 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002533
Eliad Pellerc29bb002011-10-10 10:13:03 +02002534 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002535 ret = wl1271_ps_set_mode(wl, wlvif,
2536 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002537 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002538 }
2539
Eliad Peller6bd65022011-10-10 10:13:11 +02002540 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002541 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002542 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002543 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002544
Eliad Peller6bd65022011-10-10 10:13:11 +02002545 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002546 }
2547
Eliad Peller9f259c42011-10-10 10:13:12 +02002548 return 0;
2549}
2550
2551static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2552{
2553 struct wl1271 *wl = hw->priv;
2554 struct wl12xx_vif *wlvif;
2555 struct ieee80211_conf *conf = &hw->conf;
2556 int channel, ret = 0;
2557
2558 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2559
2560 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2561 " changed 0x%x",
2562 channel,
2563 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2564 conf->power_level,
2565 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2566 changed);
2567
2568 /*
2569 * mac80211 will go to idle nearly immediately after transmitting some
2570 * frames, such as the deauth. To make sure those frames reach the air,
2571 * wait here until the TX queue is fully flushed.
2572 */
2573 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2574 (conf->flags & IEEE80211_CONF_IDLE))
2575 wl1271_tx_flush(wl);
2576
2577 mutex_lock(&wl->mutex);
2578
2579 /* we support configuring the channel and band even while off */
2580 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2581 wl->band = conf->channel->band;
2582 wl->channel = channel;
2583 }
2584
2585 if (changed & IEEE80211_CONF_CHANGE_POWER)
2586 wl->power_level = conf->power_level;
2587
2588 if (unlikely(wl->state == WL1271_STATE_OFF))
2589 goto out;
2590
2591 ret = wl1271_ps_elp_wakeup(wl);
2592 if (ret < 0)
2593 goto out;
2594
2595 /* configure each interface */
2596 wl12xx_for_each_wlvif(wl, wlvif) {
2597 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2598 if (ret < 0)
2599 goto out_sleep;
2600 }
2601
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002602out_sleep:
2603 wl1271_ps_elp_sleep(wl);
2604
2605out:
2606 mutex_unlock(&wl->mutex);
2607
2608 return ret;
2609}
2610
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002611struct wl1271_filter_params {
2612 bool enabled;
2613 int mc_list_length;
2614 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2615};
2616
Jiri Pirko22bedad2010-04-01 21:22:57 +00002617static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2618 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002619{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002620 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002621 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002622 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002623
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002624 if (unlikely(wl->state == WL1271_STATE_OFF))
2625 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002626
Juuso Oikarinen74441132009-10-13 12:47:53 +03002627 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002628 if (!fp) {
2629 wl1271_error("Out of memory setting filters.");
2630 return 0;
2631 }
2632
2633 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002634 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002635 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2636 fp->enabled = false;
2637 } else {
2638 fp->enabled = true;
2639 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002640 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002641 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002642 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002643 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002644 }
2645
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002646 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002647}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002648
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002649#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2650 FIF_ALLMULTI | \
2651 FIF_FCSFAIL | \
2652 FIF_BCN_PRBRESP_PROMISC | \
2653 FIF_CONTROL | \
2654 FIF_OTHER_BSS)
2655
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002656static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2657 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002658 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002659{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002660 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002661 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002662 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002663
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002664 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002665
Arik Nemtsov7d057862010-10-16 19:25:35 +02002666 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2667 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002668
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002669 mutex_lock(&wl->mutex);
2670
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002671 *total &= WL1271_SUPPORTED_FILTERS;
2672 changed &= WL1271_SUPPORTED_FILTERS;
2673
2674 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002675 goto out;
2676
Ido Yariva6208652011-03-01 15:14:41 +02002677 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002678 if (ret < 0)
2679 goto out;
2680
Eliad Peller6e8cd332011-10-10 10:13:13 +02002681 wl12xx_for_each_wlvif(wl, wlvif) {
2682 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2683 if (*total & FIF_ALLMULTI)
2684 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2685 false,
2686 NULL, 0);
2687 else if (fp)
2688 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2689 fp->enabled,
2690 fp->mc_list,
2691 fp->mc_list_length);
2692 if (ret < 0)
2693 goto out_sleep;
2694 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002695 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002696
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002697 /*
2698 * the fw doesn't provide an api to configure the filters. instead,
2699 * the filters configuration is based on the active roles / ROC
2700 * state.
2701 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002702
2703out_sleep:
2704 wl1271_ps_elp_sleep(wl);
2705
2706out:
2707 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002708 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002709}
2710
Eliad Peller170d0e62011-10-05 11:56:06 +02002711static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2712 u8 id, u8 key_type, u8 key_size,
2713 const u8 *key, u8 hlid, u32 tx_seq_32,
2714 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002715{
2716 struct wl1271_ap_key *ap_key;
2717 int i;
2718
2719 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2720
2721 if (key_size > MAX_KEY_SIZE)
2722 return -EINVAL;
2723
2724 /*
2725 * Find next free entry in ap_keys. Also check we are not replacing
2726 * an existing key.
2727 */
2728 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002729 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002730 break;
2731
Eliad Peller170d0e62011-10-05 11:56:06 +02002732 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002733 wl1271_warning("trying to record key replacement");
2734 return -EINVAL;
2735 }
2736 }
2737
2738 if (i == MAX_NUM_KEYS)
2739 return -EBUSY;
2740
2741 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2742 if (!ap_key)
2743 return -ENOMEM;
2744
2745 ap_key->id = id;
2746 ap_key->key_type = key_type;
2747 ap_key->key_size = key_size;
2748 memcpy(ap_key->key, key, key_size);
2749 ap_key->hlid = hlid;
2750 ap_key->tx_seq_32 = tx_seq_32;
2751 ap_key->tx_seq_16 = tx_seq_16;
2752
Eliad Peller170d0e62011-10-05 11:56:06 +02002753 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002754 return 0;
2755}
2756
Eliad Peller170d0e62011-10-05 11:56:06 +02002757static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002758{
2759 int i;
2760
2761 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002762 kfree(wlvif->ap.recorded_keys[i]);
2763 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002764 }
2765}
2766
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002767static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002768{
2769 int i, ret = 0;
2770 struct wl1271_ap_key *key;
2771 bool wep_key_added = false;
2772
2773 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002774 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002775 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002776 break;
2777
Eliad Peller170d0e62011-10-05 11:56:06 +02002778 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002779 hlid = key->hlid;
2780 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002781 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002782
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002783 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002784 key->id, key->key_type,
2785 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002786 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002787 key->tx_seq_16);
2788 if (ret < 0)
2789 goto out;
2790
2791 if (key->key_type == KEY_WEP)
2792 wep_key_added = true;
2793 }
2794
2795 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002796 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002797 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002798 if (ret < 0)
2799 goto out;
2800 }
2801
2802out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002803 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002804 return ret;
2805}
2806
Eliad Peller536129c2011-10-05 11:55:45 +02002807static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2808 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002809 u8 key_size, const u8 *key, u32 tx_seq_32,
2810 u16 tx_seq_16, struct ieee80211_sta *sta)
2811{
2812 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002813 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002814
2815 if (is_ap) {
2816 struct wl1271_station *wl_sta;
2817 u8 hlid;
2818
2819 if (sta) {
2820 wl_sta = (struct wl1271_station *)sta->drv_priv;
2821 hlid = wl_sta->hlid;
2822 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002823 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002824 }
2825
Eliad Peller53d40d02011-10-10 10:13:02 +02002826 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002827 /*
2828 * We do not support removing keys after AP shutdown.
2829 * Pretend we do to make mac80211 happy.
2830 */
2831 if (action != KEY_ADD_OR_REPLACE)
2832 return 0;
2833
Eliad Peller170d0e62011-10-05 11:56:06 +02002834 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002835 key_type, key_size,
2836 key, hlid, tx_seq_32,
2837 tx_seq_16);
2838 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002839 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002840 id, key_type, key_size,
2841 key, hlid, tx_seq_32,
2842 tx_seq_16);
2843 }
2844
2845 if (ret < 0)
2846 return ret;
2847 } else {
2848 const u8 *addr;
2849 static const u8 bcast_addr[ETH_ALEN] = {
2850 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2851 };
2852
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002853 /*
2854 * A STA set to GEM cipher requires 2 tx spare blocks.
2855 * Return to default value when GEM cipher key is removed
2856 */
2857 if (key_type == KEY_GEM) {
2858 if (action == KEY_ADD_OR_REPLACE)
2859 wl->tx_spare_blocks = 2;
2860 else if (action == KEY_REMOVE)
2861 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2862 }
2863
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002864 addr = sta ? sta->addr : bcast_addr;
2865
2866 if (is_zero_ether_addr(addr)) {
2867 /* We dont support TX only encryption */
2868 return -EOPNOTSUPP;
2869 }
2870
2871 /* The wl1271 does not allow to remove unicast keys - they
2872 will be cleared automatically on next CMD_JOIN. Ignore the
2873 request silently, as we dont want the mac80211 to emit
2874 an error message. */
2875 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2876 return 0;
2877
Eliad Peller010d3d32011-08-14 13:17:31 +03002878 /* don't remove key if hlid was already deleted */
2879 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002880 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002881 return 0;
2882
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002883 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002884 id, key_type, key_size,
2885 key, addr, tx_seq_32,
2886 tx_seq_16);
2887 if (ret < 0)
2888 return ret;
2889
2890 /* the default WEP key needs to be configured at least once */
2891 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002892 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002893 wlvif->default_key,
2894 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002895 if (ret < 0)
2896 return ret;
2897 }
2898 }
2899
2900 return 0;
2901}
2902
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002903static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2904 struct ieee80211_vif *vif,
2905 struct ieee80211_sta *sta,
2906 struct ieee80211_key_conf *key_conf)
2907{
2908 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002909 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002910 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002911 u32 tx_seq_32 = 0;
2912 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002913 u8 key_type;
2914
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002915 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2916
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002917 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002918 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002919 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002920 key_conf->keylen, key_conf->flags);
2921 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2922
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002923 mutex_lock(&wl->mutex);
2924
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002925 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2926 ret = -EAGAIN;
2927 goto out_unlock;
2928 }
2929
Ido Yariva6208652011-03-01 15:14:41 +02002930 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002931 if (ret < 0)
2932 goto out_unlock;
2933
Johannes Berg97359d12010-08-10 09:46:38 +02002934 switch (key_conf->cipher) {
2935 case WLAN_CIPHER_SUITE_WEP40:
2936 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002937 key_type = KEY_WEP;
2938
2939 key_conf->hw_key_idx = key_conf->keyidx;
2940 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002941 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002942 key_type = KEY_TKIP;
2943
2944 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002945 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2946 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002947 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002948 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002949 key_type = KEY_AES;
2950
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002951 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002952 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2953 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002954 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002955 case WL1271_CIPHER_SUITE_GEM:
2956 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002957 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2958 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002959 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002960 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002961 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002962
2963 ret = -EOPNOTSUPP;
2964 goto out_sleep;
2965 }
2966
2967 switch (cmd) {
2968 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002969 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002970 key_conf->keyidx, key_type,
2971 key_conf->keylen, key_conf->key,
2972 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002973 if (ret < 0) {
2974 wl1271_error("Could not add or replace key");
2975 goto out_sleep;
2976 }
2977 break;
2978
2979 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002980 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002981 key_conf->keyidx, key_type,
2982 key_conf->keylen, key_conf->key,
2983 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002984 if (ret < 0) {
2985 wl1271_error("Could not remove key");
2986 goto out_sleep;
2987 }
2988 break;
2989
2990 default:
2991 wl1271_error("Unsupported key cmd 0x%x", cmd);
2992 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002993 break;
2994 }
2995
2996out_sleep:
2997 wl1271_ps_elp_sleep(wl);
2998
2999out_unlock:
3000 mutex_unlock(&wl->mutex);
3001
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003002 return ret;
3003}
3004
3005static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003006 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003007 struct cfg80211_scan_request *req)
3008{
3009 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003010 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3011
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003012 int ret;
3013 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003014 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003015
3016 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3017
3018 if (req->n_ssids) {
3019 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003020 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003021 }
3022
3023 mutex_lock(&wl->mutex);
3024
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003025 if (wl->state == WL1271_STATE_OFF) {
3026 /*
3027 * We cannot return -EBUSY here because cfg80211 will expect
3028 * a call to ieee80211_scan_completed if we do - in this case
3029 * there won't be any call.
3030 */
3031 ret = -EAGAIN;
3032 goto out;
3033 }
3034
Ido Yariva6208652011-03-01 15:14:41 +02003035 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003036 if (ret < 0)
3037 goto out;
3038
Eliad Peller92e712d2011-12-18 20:25:43 +02003039 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
3040 test_bit(wlvif->role_id, wl->roc_map)) {
3041 /* don't allow scanning right now */
3042 ret = -EBUSY;
3043 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003044 }
3045
Eliad Peller92e712d2011-12-18 20:25:43 +02003046 /* cancel ROC before scanning */
3047 if (wl12xx_dev_role_started(wlvif))
3048 wl12xx_stop_dev(wl, wlvif);
3049
Eliad Peller784f6942011-10-05 11:55:39 +02003050 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003051out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003052 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003053out:
3054 mutex_unlock(&wl->mutex);
3055
3056 return ret;
3057}
3058
Eliad Peller73ecce32011-06-27 13:06:45 +03003059static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3060 struct ieee80211_vif *vif)
3061{
3062 struct wl1271 *wl = hw->priv;
3063 int ret;
3064
3065 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3066
3067 mutex_lock(&wl->mutex);
3068
3069 if (wl->state == WL1271_STATE_OFF)
3070 goto out;
3071
3072 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3073 goto out;
3074
3075 ret = wl1271_ps_elp_wakeup(wl);
3076 if (ret < 0)
3077 goto out;
3078
3079 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3080 ret = wl1271_scan_stop(wl);
3081 if (ret < 0)
3082 goto out_sleep;
3083 }
3084 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3085 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003086 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003087 wl->scan.req = NULL;
3088 ieee80211_scan_completed(wl->hw, true);
3089
3090out_sleep:
3091 wl1271_ps_elp_sleep(wl);
3092out:
3093 mutex_unlock(&wl->mutex);
3094
3095 cancel_delayed_work_sync(&wl->scan_complete_work);
3096}
3097
Luciano Coelho33c2c062011-05-10 14:46:02 +03003098static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3099 struct ieee80211_vif *vif,
3100 struct cfg80211_sched_scan_request *req,
3101 struct ieee80211_sched_scan_ies *ies)
3102{
3103 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003104 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003105 int ret;
3106
3107 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3108
3109 mutex_lock(&wl->mutex);
3110
3111 ret = wl1271_ps_elp_wakeup(wl);
3112 if (ret < 0)
3113 goto out;
3114
Eliad Peller536129c2011-10-05 11:55:45 +02003115 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003116 if (ret < 0)
3117 goto out_sleep;
3118
Eliad Peller536129c2011-10-05 11:55:45 +02003119 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003120 if (ret < 0)
3121 goto out_sleep;
3122
3123 wl->sched_scanning = true;
3124
3125out_sleep:
3126 wl1271_ps_elp_sleep(wl);
3127out:
3128 mutex_unlock(&wl->mutex);
3129 return ret;
3130}
3131
3132static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3133 struct ieee80211_vif *vif)
3134{
3135 struct wl1271 *wl = hw->priv;
3136 int ret;
3137
3138 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3139
3140 mutex_lock(&wl->mutex);
3141
3142 ret = wl1271_ps_elp_wakeup(wl);
3143 if (ret < 0)
3144 goto out;
3145
3146 wl1271_scan_sched_scan_stop(wl);
3147
3148 wl1271_ps_elp_sleep(wl);
3149out:
3150 mutex_unlock(&wl->mutex);
3151}
3152
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003153static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3154{
3155 struct wl1271 *wl = hw->priv;
3156 int ret = 0;
3157
3158 mutex_lock(&wl->mutex);
3159
3160 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3161 ret = -EAGAIN;
3162 goto out;
3163 }
3164
Ido Yariva6208652011-03-01 15:14:41 +02003165 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003166 if (ret < 0)
3167 goto out;
3168
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003169 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003170 if (ret < 0)
3171 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3172
3173 wl1271_ps_elp_sleep(wl);
3174
3175out:
3176 mutex_unlock(&wl->mutex);
3177
3178 return ret;
3179}
3180
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003181static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3182{
3183 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003184 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003185 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003186
3187 mutex_lock(&wl->mutex);
3188
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003189 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3190 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003191 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003192 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003193
Ido Yariva6208652011-03-01 15:14:41 +02003194 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003195 if (ret < 0)
3196 goto out;
3197
Eliad Peller6e8cd332011-10-10 10:13:13 +02003198 wl12xx_for_each_wlvif(wl, wlvif) {
3199 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3200 if (ret < 0)
3201 wl1271_warning("set rts threshold failed: %d", ret);
3202 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003203 wl1271_ps_elp_sleep(wl);
3204
3205out:
3206 mutex_unlock(&wl->mutex);
3207
3208 return ret;
3209}
3210
Eliad Peller1fe9f162011-10-05 11:55:48 +02003211static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003212 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003213{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003214 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003215 u8 ssid_len;
3216 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3217 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003218
Eliad Peller889cb362011-05-01 09:56:45 +03003219 if (!ptr) {
3220 wl1271_error("No SSID in IEs!");
3221 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003222 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003223
Eliad Peller889cb362011-05-01 09:56:45 +03003224 ssid_len = ptr[1];
3225 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3226 wl1271_error("SSID is too long!");
3227 return -EINVAL;
3228 }
3229
Eliad Peller1fe9f162011-10-05 11:55:48 +02003230 wlvif->ssid_len = ssid_len;
3231 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003232 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003233}
3234
Eliad Pellerd48055d2011-09-15 12:07:04 +03003235static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3236{
3237 int len;
3238 const u8 *next, *end = skb->data + skb->len;
3239 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3240 skb->len - ieoffset);
3241 if (!ie)
3242 return;
3243 len = ie[1] + 2;
3244 next = ie + len;
3245 memmove(ie, next, end - next);
3246 skb_trim(skb, skb->len - len);
3247}
3248
Eliad Peller26b4bf22011-09-15 12:07:05 +03003249static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3250 unsigned int oui, u8 oui_type,
3251 int ieoffset)
3252{
3253 int len;
3254 const u8 *next, *end = skb->data + skb->len;
3255 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3256 skb->data + ieoffset,
3257 skb->len - ieoffset);
3258 if (!ie)
3259 return;
3260 len = ie[1] + 2;
3261 next = ie + len;
3262 memmove(ie, next, end - next);
3263 skb_trim(skb, skb->len - len);
3264}
3265
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003266static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3267 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003268{
3269 struct sk_buff *skb;
3270 int ret;
3271
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003272 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003273 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003274 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003275
3276 ret = wl1271_cmd_template_set(wl,
3277 CMD_TEMPL_AP_PROBE_RESPONSE,
3278 skb->data,
3279 skb->len, 0,
3280 rates);
3281
3282 dev_kfree_skb(skb);
3283 return ret;
3284}
3285
3286static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3287 struct ieee80211_vif *vif,
3288 u8 *probe_rsp_data,
3289 size_t probe_rsp_len,
3290 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003291{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003292 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3293 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003294 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3295 int ssid_ie_offset, ie_offset, templ_len;
3296 const u8 *ptr;
3297
3298 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003299 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003300 return wl1271_cmd_template_set(wl,
3301 CMD_TEMPL_AP_PROBE_RESPONSE,
3302 probe_rsp_data,
3303 probe_rsp_len, 0,
3304 rates);
3305
3306 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3307 wl1271_error("probe_rsp template too big");
3308 return -EINVAL;
3309 }
3310
3311 /* start searching from IE offset */
3312 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3313
3314 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3315 probe_rsp_len - ie_offset);
3316 if (!ptr) {
3317 wl1271_error("No SSID in beacon!");
3318 return -EINVAL;
3319 }
3320
3321 ssid_ie_offset = ptr - probe_rsp_data;
3322 ptr += (ptr[1] + 2);
3323
3324 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3325
3326 /* insert SSID from bss_conf */
3327 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3328 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3329 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3330 bss_conf->ssid, bss_conf->ssid_len);
3331 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3332
3333 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3334 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3335 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3336
3337 return wl1271_cmd_template_set(wl,
3338 CMD_TEMPL_AP_PROBE_RESPONSE,
3339 probe_rsp_templ,
3340 templ_len, 0,
3341 rates);
3342}
3343
Arik Nemtsove78a2872010-10-16 19:07:21 +02003344static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003345 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003346 struct ieee80211_bss_conf *bss_conf,
3347 u32 changed)
3348{
Eliad Peller0603d892011-10-05 11:55:51 +02003349 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003350 int ret = 0;
3351
3352 if (changed & BSS_CHANGED_ERP_SLOT) {
3353 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003354 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003355 else
Eliad Peller0603d892011-10-05 11:55:51 +02003356 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003357 if (ret < 0) {
3358 wl1271_warning("Set slot time failed %d", ret);
3359 goto out;
3360 }
3361 }
3362
3363 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3364 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003365 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003366 else
Eliad Peller0603d892011-10-05 11:55:51 +02003367 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003368 }
3369
3370 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3371 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003372 ret = wl1271_acx_cts_protect(wl, wlvif,
3373 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003374 else
Eliad Peller0603d892011-10-05 11:55:51 +02003375 ret = wl1271_acx_cts_protect(wl, wlvif,
3376 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003377 if (ret < 0) {
3378 wl1271_warning("Set ctsprotect failed %d", ret);
3379 goto out;
3380 }
3381 }
3382
3383out:
3384 return ret;
3385}
3386
3387static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3388 struct ieee80211_vif *vif,
3389 struct ieee80211_bss_conf *bss_conf,
3390 u32 changed)
3391{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003392 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003393 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003394 int ret = 0;
3395
3396 if ((changed & BSS_CHANGED_BEACON_INT)) {
3397 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3398 bss_conf->beacon_int);
3399
Eliad Peller6a899792011-10-05 11:55:58 +02003400 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003401 }
3402
Arik Nemtsov560f0022011-11-08 18:46:54 +02003403 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3404 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003405 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3406 wl1271_debug(DEBUG_AP, "probe response updated");
3407 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3408 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003409 }
3410
Arik Nemtsove78a2872010-10-16 19:07:21 +02003411 if ((changed & BSS_CHANGED_BEACON)) {
3412 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003413 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003414 int ieoffset = offsetof(struct ieee80211_mgmt,
3415 u.beacon.variable);
3416 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3417 u16 tmpl_id;
3418
Arik Nemtsov560f0022011-11-08 18:46:54 +02003419 if (!beacon) {
3420 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003421 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003422 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003423
3424 wl1271_debug(DEBUG_MASTER, "beacon updated");
3425
Eliad Peller1fe9f162011-10-05 11:55:48 +02003426 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003427 if (ret < 0) {
3428 dev_kfree_skb(beacon);
3429 goto out;
3430 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003431 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003432 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3433 CMD_TEMPL_BEACON;
3434 ret = wl1271_cmd_template_set(wl, tmpl_id,
3435 beacon->data,
3436 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003437 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003438 if (ret < 0) {
3439 dev_kfree_skb(beacon);
3440 goto out;
3441 }
3442
Arik Nemtsov560f0022011-11-08 18:46:54 +02003443 /*
3444 * In case we already have a probe-resp beacon set explicitly
3445 * by usermode, don't use the beacon data.
3446 */
3447 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3448 goto end_bcn;
3449
Eliad Pellerd48055d2011-09-15 12:07:04 +03003450 /* remove TIM ie from probe response */
3451 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3452
Eliad Peller26b4bf22011-09-15 12:07:05 +03003453 /*
3454 * remove p2p ie from probe response.
3455 * the fw reponds to probe requests that don't include
3456 * the p2p ie. probe requests with p2p ie will be passed,
3457 * and will be responded by the supplicant (the spec
3458 * forbids including the p2p ie when responding to probe
3459 * requests that didn't include it).
3460 */
3461 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3462 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3463
Arik Nemtsove78a2872010-10-16 19:07:21 +02003464 hdr = (struct ieee80211_hdr *) beacon->data;
3465 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3466 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003467 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003468 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003469 beacon->data,
3470 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003471 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003472 else
3473 ret = wl1271_cmd_template_set(wl,
3474 CMD_TEMPL_PROBE_RESPONSE,
3475 beacon->data,
3476 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003477 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003478end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003479 dev_kfree_skb(beacon);
3480 if (ret < 0)
3481 goto out;
3482 }
3483
3484out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003485 if (ret != 0)
3486 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003487 return ret;
3488}
3489
3490/* AP mode changes */
3491static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003492 struct ieee80211_vif *vif,
3493 struct ieee80211_bss_conf *bss_conf,
3494 u32 changed)
3495{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003496 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003497 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003498
Arik Nemtsove78a2872010-10-16 19:07:21 +02003499 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3500 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003501
Eliad Peller87fbcb02011-10-05 11:55:41 +02003502 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003503 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003504 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003505 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003506
Eliad Peller87fbcb02011-10-05 11:55:41 +02003507 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003508 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003509 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003510 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003511 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003512
Eliad Peller784f6942011-10-05 11:55:39 +02003513 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003514 if (ret < 0)
3515 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003516 }
3517
Arik Nemtsove78a2872010-10-16 19:07:21 +02003518 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3519 if (ret < 0)
3520 goto out;
3521
3522 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3523 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003524 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003525 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003526 if (ret < 0)
3527 goto out;
3528
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003529 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003530 if (ret < 0)
3531 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003532
Eliad Peller53d40d02011-10-10 10:13:02 +02003533 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003534 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003535 }
3536 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003537 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003538 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003539 if (ret < 0)
3540 goto out;
3541
Eliad Peller53d40d02011-10-10 10:13:02 +02003542 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003543 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3544 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003545 wl1271_debug(DEBUG_AP, "stopped AP");
3546 }
3547 }
3548 }
3549
Eliad Peller0603d892011-10-05 11:55:51 +02003550 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003551 if (ret < 0)
3552 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003553
3554 /* Handle HT information change */
3555 if ((changed & BSS_CHANGED_HT) &&
3556 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003557 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003558 bss_conf->ht_operation_mode);
3559 if (ret < 0) {
3560 wl1271_warning("Set ht information failed %d", ret);
3561 goto out;
3562 }
3563 }
3564
Arik Nemtsove78a2872010-10-16 19:07:21 +02003565out:
3566 return;
3567}
3568
3569/* STA/IBSS mode changes */
3570static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3571 struct ieee80211_vif *vif,
3572 struct ieee80211_bss_conf *bss_conf,
3573 u32 changed)
3574{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003575 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003576 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003577 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003578 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003579 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003580 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003581 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003582 bool sta_exists = false;
3583 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003584
3585 if (is_ibss) {
3586 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3587 changed);
3588 if (ret < 0)
3589 goto out;
3590 }
3591
Eliad Peller227e81e2011-08-14 13:17:26 +03003592 if (changed & BSS_CHANGED_IBSS) {
3593 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003594 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003595 ibss_joined = true;
3596 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003597 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3598 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003599 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003600 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003601 }
3602 }
3603 }
3604
3605 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003606 do_join = true;
3607
3608 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003609 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003610 do_join = true;
3611
Eliad Peller227e81e2011-08-14 13:17:26 +03003612 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003613 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3614 bss_conf->enable_beacon ? "enabled" : "disabled");
3615
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003616 do_join = true;
3617 }
3618
Eliad Pellerc31e4942011-10-23 08:21:55 +02003619 if (changed & BSS_CHANGED_IDLE) {
3620 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3621 if (ret < 0)
3622 wl1271_warning("idle mode change failed %d", ret);
3623 }
3624
Arik Nemtsove78a2872010-10-16 19:07:21 +02003625 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003626 bool enable = false;
3627 if (bss_conf->cqm_rssi_thold)
3628 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003629 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003630 bss_conf->cqm_rssi_thold,
3631 bss_conf->cqm_rssi_hyst);
3632 if (ret < 0)
3633 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003634 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003635 }
3636
Eliad Pellercdf09492011-10-05 11:55:44 +02003637 if (changed & BSS_CHANGED_BSSID)
3638 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003639 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003640 if (ret < 0)
3641 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003642
Eliad Peller784f6942011-10-05 11:55:39 +02003643 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003644 if (ret < 0)
3645 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003646
Eliad Pellerfa287b82010-12-26 09:27:50 +01003647 /* Need to update the BSSID (for filtering etc) */
3648 do_join = true;
3649 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003650
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003651 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3652 rcu_read_lock();
3653 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3654 if (!sta)
3655 goto sta_not_found;
3656
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003657 /* save the supp_rates of the ap */
3658 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3659 if (sta->ht_cap.ht_supported)
3660 sta_rate_set |=
3661 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003662 sta_ht_cap = sta->ht_cap;
3663 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003664
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003665sta_not_found:
3666 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003667 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003668
Arik Nemtsove78a2872010-10-16 19:07:21 +02003669 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003670 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003671 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003672 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003673 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003674 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003675
Eliad Peller74ec8392011-10-05 11:56:02 +02003676 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003677
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003678 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003679 * use basic rates from AP, and determine lowest rate
3680 * to use with control frames.
3681 */
3682 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003683 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003684 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003685 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003686 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003687 wl1271_tx_min_rate_get(wl,
3688 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003689 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003690 wlvif->rate_set =
3691 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003692 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003693 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003694 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003695 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003696 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003697
3698 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003699 * with wl1271, we don't need to update the
3700 * beacon_int and dtim_period, because the firmware
3701 * updates it by itself when the first beacon is
3702 * received after a join.
3703 */
Eliad Peller6840e372011-10-05 11:55:50 +02003704 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003705 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003706 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003707
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003708 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003709 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003710 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003711 dev_kfree_skb(wlvif->probereq);
3712 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003713 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003714 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003715 ieoffset = offsetof(struct ieee80211_mgmt,
3716 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003717 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003718
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003719 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003720 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003721 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003722 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003723 } else {
3724 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003725 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003726 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3727 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003728 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003729 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3730 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003731 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003732
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003733 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003734 dev_kfree_skb(wlvif->probereq);
3735 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003736
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003737 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003738 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003739
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003740 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003741 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003742 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003743 wl1271_tx_min_rate_get(wl,
3744 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003745 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003746 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003747 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003748
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003749 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003750 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003751
3752 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003753 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003754 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003755 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003756
3757 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003758 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003759 u32 conf_flags = wl->hw->conf.flags;
3760 /*
3761 * we might have to disable roc, if there was
3762 * no IF_OPER_UP notification.
3763 */
3764 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003765 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003766 if (ret < 0)
3767 goto out;
3768 }
3769 /*
3770 * (we also need to disable roc in case of
3771 * roaming on the same channel. until we will
3772 * have a better flow...)
3773 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003774 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3775 ret = wl12xx_croc(wl,
3776 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003777 if (ret < 0)
3778 goto out;
3779 }
3780
Eliad Peller0603d892011-10-05 11:55:51 +02003781 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003782 if (!(conf_flags & IEEE80211_CONF_IDLE))
3783 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003784 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003785 }
3786 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003787
Eliad Pellerd192d262011-05-24 14:33:08 +03003788 if (changed & BSS_CHANGED_IBSS) {
3789 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3790 bss_conf->ibss_joined);
3791
3792 if (bss_conf->ibss_joined) {
3793 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003794 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003795 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003796 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003797 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003798 wl1271_tx_min_rate_get(wl,
3799 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003800
Shahar Levi06b660e2011-09-05 13:54:36 +03003801 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003802 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3803 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003804 if (ret < 0)
3805 goto out;
3806 }
3807 }
3808
Eliad Peller0603d892011-10-05 11:55:51 +02003809 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003810 if (ret < 0)
3811 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003812
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003813 if (changed & BSS_CHANGED_ARP_FILTER) {
3814 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003815 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003816
Eliad Pellerc5312772010-12-09 11:31:27 +02003817 if (bss_conf->arp_addr_cnt == 1 &&
3818 bss_conf->arp_filter_enabled) {
3819 /*
3820 * The template should have been configured only upon
3821 * association. however, it seems that the correct ip
3822 * isn't being set (when sending), so we have to
3823 * reconfigure the template upon every ip change.
3824 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003825 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003826 if (ret < 0) {
3827 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003828 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003829 }
3830
Eliad Peller0603d892011-10-05 11:55:51 +02003831 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003832 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003833 addr);
3834 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003835 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003836
3837 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003838 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003839 }
3840
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003841 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003842 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003843 if (ret < 0) {
3844 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003845 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003846 }
Eliad Peller251c1772011-08-14 13:17:17 +03003847
3848 /* ROC until connected (after EAPOL exchange) */
3849 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003850 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003851 if (ret < 0)
3852 goto out;
3853
Eliad Pellerba8447f2011-10-10 10:13:00 +02003854 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003855 ieee80211_get_operstate(vif));
3856 }
3857 /*
3858 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003859 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003860 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003861 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003862 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003863 if (ret < 0)
3864 goto out;
3865 }
Eliad Peller05dba352011-08-23 16:37:01 +03003866
3867 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003868 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3869 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003870 enum wl1271_cmd_ps_mode mode;
3871
3872 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003873 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003874 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003875 true);
3876 if (ret < 0)
3877 goto out;
3878 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003879 }
3880
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003881 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003882 if (sta_exists) {
3883 if ((changed & BSS_CHANGED_HT) &&
3884 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003885 ret = wl1271_acx_set_ht_capabilities(wl,
3886 &sta_ht_cap,
3887 true,
Eliad Peller154da672011-10-05 11:55:53 +02003888 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003889 if (ret < 0) {
3890 wl1271_warning("Set ht cap true failed %d",
3891 ret);
3892 goto out;
3893 }
3894 }
3895 /* handle new association without HT and disassociation */
3896 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003897 ret = wl1271_acx_set_ht_capabilities(wl,
3898 &sta_ht_cap,
3899 false,
Eliad Peller154da672011-10-05 11:55:53 +02003900 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003901 if (ret < 0) {
3902 wl1271_warning("Set ht cap false failed %d",
3903 ret);
3904 goto out;
3905 }
3906 }
3907 }
3908
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003909 /* Handle HT information change. Done after join. */
3910 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003911 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003912 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003913 bss_conf->ht_operation_mode);
3914 if (ret < 0) {
3915 wl1271_warning("Set ht information failed %d", ret);
3916 goto out;
3917 }
3918 }
3919
Arik Nemtsove78a2872010-10-16 19:07:21 +02003920out:
3921 return;
3922}
3923
3924static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3925 struct ieee80211_vif *vif,
3926 struct ieee80211_bss_conf *bss_conf,
3927 u32 changed)
3928{
3929 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003930 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3931 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003932 int ret;
3933
3934 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3935 (int)changed);
3936
3937 mutex_lock(&wl->mutex);
3938
3939 if (unlikely(wl->state == WL1271_STATE_OFF))
3940 goto out;
3941
Eliad Peller10c8cd02011-10-10 10:13:06 +02003942 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3943 goto out;
3944
Ido Yariva6208652011-03-01 15:14:41 +02003945 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003946 if (ret < 0)
3947 goto out;
3948
3949 if (is_ap)
3950 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3951 else
3952 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3953
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003954 wl1271_ps_elp_sleep(wl);
3955
3956out:
3957 mutex_unlock(&wl->mutex);
3958}
3959
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003960static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3961 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003962 const struct ieee80211_tx_queue_params *params)
3963{
3964 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003965 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003966 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003967 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003968
3969 mutex_lock(&wl->mutex);
3970
3971 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3972
Kalle Valo4695dc92010-03-18 12:26:38 +02003973 if (params->uapsd)
3974 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3975 else
3976 ps_scheme = CONF_PS_SCHEME_LEGACY;
3977
Eliad Peller5b37ddf2011-12-18 20:25:40 +02003978 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003979 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003980
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003981 ret = wl1271_ps_elp_wakeup(wl);
3982 if (ret < 0)
3983 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003984
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003985 /*
3986 * the txop is confed in units of 32us by the mac80211,
3987 * we need us
3988 */
Eliad Peller0603d892011-10-05 11:55:51 +02003989 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003990 params->cw_min, params->cw_max,
3991 params->aifs, params->txop << 5);
3992 if (ret < 0)
3993 goto out_sleep;
3994
Eliad Peller0603d892011-10-05 11:55:51 +02003995 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003996 CONF_CHANNEL_TYPE_EDCF,
3997 wl1271_tx_get_queue(queue),
3998 ps_scheme, CONF_ACK_POLICY_LEGACY,
3999 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004000
4001out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004002 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004003
4004out:
4005 mutex_unlock(&wl->mutex);
4006
4007 return ret;
4008}
4009
Eliad Peller37a41b42011-09-21 14:06:11 +03004010static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4011 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004012{
4013
4014 struct wl1271 *wl = hw->priv;
4015 u64 mactime = ULLONG_MAX;
4016 int ret;
4017
4018 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4019
4020 mutex_lock(&wl->mutex);
4021
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004022 if (unlikely(wl->state == WL1271_STATE_OFF))
4023 goto out;
4024
Ido Yariva6208652011-03-01 15:14:41 +02004025 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004026 if (ret < 0)
4027 goto out;
4028
4029 ret = wl1271_acx_tsf_info(wl, &mactime);
4030 if (ret < 0)
4031 goto out_sleep;
4032
4033out_sleep:
4034 wl1271_ps_elp_sleep(wl);
4035
4036out:
4037 mutex_unlock(&wl->mutex);
4038 return mactime;
4039}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004040
John W. Linvilleece550d2010-07-28 16:41:06 -04004041static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4042 struct survey_info *survey)
4043{
4044 struct wl1271 *wl = hw->priv;
4045 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004046
John W. Linvilleece550d2010-07-28 16:41:06 -04004047 if (idx != 0)
4048 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004049
John W. Linvilleece550d2010-07-28 16:41:06 -04004050 survey->channel = conf->channel;
4051 survey->filled = SURVEY_INFO_NOISE_DBM;
4052 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004053
John W. Linvilleece550d2010-07-28 16:41:06 -04004054 return 0;
4055}
4056
Arik Nemtsov409622e2011-02-23 00:22:29 +02004057static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004058 struct wl12xx_vif *wlvif,
4059 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004060{
4061 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004062 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004063
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004064
4065 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004066 wl1271_warning("could not allocate HLID - too much stations");
4067 return -EBUSY;
4068 }
4069
4070 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004071 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4072 if (ret < 0) {
4073 wl1271_warning("could not allocate HLID - too many links");
4074 return -EBUSY;
4075 }
4076
4077 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004078 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004079 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004080 return 0;
4081}
4082
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004083void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004084{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004085 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004086 return;
4087
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004088 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004089 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004090 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004091 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004092 __clear_bit(hlid, &wl->ap_ps_map);
4093 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004094 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004095 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004096}
4097
4098static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4099 struct ieee80211_vif *vif,
4100 struct ieee80211_sta *sta)
4101{
4102 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004103 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004104 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004105 int ret = 0;
4106 u8 hlid;
4107
4108 mutex_lock(&wl->mutex);
4109
4110 if (unlikely(wl->state == WL1271_STATE_OFF))
4111 goto out;
4112
Eliad Peller536129c2011-10-05 11:55:45 +02004113 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004114 goto out;
4115
4116 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4117
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004118 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004119 if (ret < 0)
4120 goto out;
4121
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004122 wl_sta = (struct wl1271_station *)sta->drv_priv;
4123 hlid = wl_sta->hlid;
4124
Ido Yariva6208652011-03-01 15:14:41 +02004125 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004126 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004127 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004128
Eliad Peller1b92f152011-10-10 10:13:09 +02004129 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004130 if (ret < 0)
4131 goto out_sleep;
4132
Eliad Pellerb67476e2011-08-14 13:17:23 +03004133 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4134 if (ret < 0)
4135 goto out_sleep;
4136
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004137 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4138 if (ret < 0)
4139 goto out_sleep;
4140
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004141out_sleep:
4142 wl1271_ps_elp_sleep(wl);
4143
Arik Nemtsov409622e2011-02-23 00:22:29 +02004144out_free_sta:
4145 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004146 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004147
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004148out:
4149 mutex_unlock(&wl->mutex);
4150 return ret;
4151}
4152
4153static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4154 struct ieee80211_vif *vif,
4155 struct ieee80211_sta *sta)
4156{
4157 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004158 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004159 struct wl1271_station *wl_sta;
4160 int ret = 0, id;
4161
4162 mutex_lock(&wl->mutex);
4163
4164 if (unlikely(wl->state == WL1271_STATE_OFF))
4165 goto out;
4166
Eliad Peller536129c2011-10-05 11:55:45 +02004167 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004168 goto out;
4169
4170 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4171
4172 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004173 id = wl_sta->hlid;
4174 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004175 goto out;
4176
Ido Yariva6208652011-03-01 15:14:41 +02004177 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004178 if (ret < 0)
4179 goto out;
4180
Eliad Pellerc690ec82011-08-14 13:17:07 +03004181 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004182 if (ret < 0)
4183 goto out_sleep;
4184
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004185 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004186
4187out_sleep:
4188 wl1271_ps_elp_sleep(wl);
4189
4190out:
4191 mutex_unlock(&wl->mutex);
4192 return ret;
4193}
4194
Luciano Coelho4623ec72011-03-21 19:26:41 +02004195static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4196 struct ieee80211_vif *vif,
4197 enum ieee80211_ampdu_mlme_action action,
4198 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4199 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004200{
4201 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004202 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004203 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004204 u8 hlid, *ba_bitmap;
4205
4206 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4207 tid);
4208
4209 /* sanity check - the fields in FW are only 8bits wide */
4210 if (WARN_ON(tid > 0xFF))
4211 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004212
4213 mutex_lock(&wl->mutex);
4214
4215 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4216 ret = -EAGAIN;
4217 goto out;
4218 }
4219
Eliad Peller536129c2011-10-05 11:55:45 +02004220 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004221 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004222 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004223 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004224 struct wl1271_station *wl_sta;
4225
4226 wl_sta = (struct wl1271_station *)sta->drv_priv;
4227 hlid = wl_sta->hlid;
4228 ba_bitmap = &wl->links[hlid].ba_bitmap;
4229 } else {
4230 ret = -EINVAL;
4231 goto out;
4232 }
4233
Ido Yariva6208652011-03-01 15:14:41 +02004234 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004235 if (ret < 0)
4236 goto out;
4237
Shahar Levi70559a02011-05-22 16:10:22 +03004238 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4239 tid, action);
4240
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004241 switch (action) {
4242 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004243 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004244 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004245 break;
4246 }
4247
4248 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4249 ret = -EBUSY;
4250 wl1271_error("exceeded max RX BA sessions");
4251 break;
4252 }
4253
4254 if (*ba_bitmap & BIT(tid)) {
4255 ret = -EINVAL;
4256 wl1271_error("cannot enable RX BA session on active "
4257 "tid: %d", tid);
4258 break;
4259 }
4260
4261 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4262 hlid);
4263 if (!ret) {
4264 *ba_bitmap |= BIT(tid);
4265 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004266 }
4267 break;
4268
4269 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004270 if (!(*ba_bitmap & BIT(tid))) {
4271 ret = -EINVAL;
4272 wl1271_error("no active RX BA session on tid: %d",
4273 tid);
4274 break;
4275 }
4276
4277 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4278 hlid);
4279 if (!ret) {
4280 *ba_bitmap &= ~BIT(tid);
4281 wl->ba_rx_session_count--;
4282 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004283 break;
4284
4285 /*
4286 * The BA initiator session management in FW independently.
4287 * Falling break here on purpose for all TX APDU commands.
4288 */
4289 case IEEE80211_AMPDU_TX_START:
4290 case IEEE80211_AMPDU_TX_STOP:
4291 case IEEE80211_AMPDU_TX_OPERATIONAL:
4292 ret = -EINVAL;
4293 break;
4294
4295 default:
4296 wl1271_error("Incorrect ampdu action id=%x\n", action);
4297 ret = -EINVAL;
4298 }
4299
4300 wl1271_ps_elp_sleep(wl);
4301
4302out:
4303 mutex_unlock(&wl->mutex);
4304
4305 return ret;
4306}
4307
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004308static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4309 struct ieee80211_vif *vif,
4310 const struct cfg80211_bitrate_mask *mask)
4311{
Eliad Peller83587502011-10-10 10:12:53 +02004312 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004313 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004314 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004315
4316 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4317 mask->control[NL80211_BAND_2GHZ].legacy,
4318 mask->control[NL80211_BAND_5GHZ].legacy);
4319
4320 mutex_lock(&wl->mutex);
4321
4322 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004323 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004324 wl1271_tx_enabled_rates_get(wl,
4325 mask->control[i].legacy,
4326 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004327
4328 if (unlikely(wl->state == WL1271_STATE_OFF))
4329 goto out;
4330
4331 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4332 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4333
4334 ret = wl1271_ps_elp_wakeup(wl);
4335 if (ret < 0)
4336 goto out;
4337
4338 wl1271_set_band_rate(wl, wlvif);
4339 wlvif->basic_rate =
4340 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4341 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4342
4343 wl1271_ps_elp_sleep(wl);
4344 }
4345out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004346 mutex_unlock(&wl->mutex);
4347
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004348 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004349}
4350
Shahar Levi6d158ff2011-09-08 13:01:33 +03004351static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4352 struct ieee80211_channel_switch *ch_switch)
4353{
4354 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004355 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004356 int ret;
4357
4358 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4359
4360 mutex_lock(&wl->mutex);
4361
4362 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004363 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4364 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4365 ieee80211_chswitch_done(vif, false);
4366 }
4367 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004368 }
4369
4370 ret = wl1271_ps_elp_wakeup(wl);
4371 if (ret < 0)
4372 goto out;
4373
Eliad Peller52630c52011-10-10 10:13:08 +02004374 /* TODO: change mac80211 to pass vif as param */
4375 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4376 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004377
Eliad Peller52630c52011-10-10 10:13:08 +02004378 if (!ret)
4379 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4380 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004381
4382 wl1271_ps_elp_sleep(wl);
4383
4384out:
4385 mutex_unlock(&wl->mutex);
4386}
4387
Arik Nemtsov33437892011-04-26 23:35:39 +03004388static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4389{
4390 struct wl1271 *wl = hw->priv;
4391 bool ret = false;
4392
4393 mutex_lock(&wl->mutex);
4394
4395 if (unlikely(wl->state == WL1271_STATE_OFF))
4396 goto out;
4397
4398 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004399 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004400out:
4401 mutex_unlock(&wl->mutex);
4402
4403 return ret;
4404}
4405
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004406/* can't be const, mac80211 writes to this */
4407static struct ieee80211_rate wl1271_rates[] = {
4408 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004409 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4410 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004411 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004412 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4413 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004414 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4415 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004416 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4417 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004418 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4419 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004420 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4421 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004422 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4423 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004424 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4425 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004426 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004427 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4428 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004429 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004430 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4431 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004432 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004433 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4434 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004435 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004436 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4437 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004438 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004439 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4440 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004441 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004442 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4443 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004444 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004445 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4446 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004447};
4448
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004449/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004450static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004451 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004452 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004453 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4454 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4455 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004456 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004457 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4458 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4459 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004460 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004461 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4462 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4463 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004464 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004465};
4466
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004467/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004468static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004469 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004470 7, /* CONF_HW_RXTX_RATE_MCS7 */
4471 6, /* CONF_HW_RXTX_RATE_MCS6 */
4472 5, /* CONF_HW_RXTX_RATE_MCS5 */
4473 4, /* CONF_HW_RXTX_RATE_MCS4 */
4474 3, /* CONF_HW_RXTX_RATE_MCS3 */
4475 2, /* CONF_HW_RXTX_RATE_MCS2 */
4476 1, /* CONF_HW_RXTX_RATE_MCS1 */
4477 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004478
4479 11, /* CONF_HW_RXTX_RATE_54 */
4480 10, /* CONF_HW_RXTX_RATE_48 */
4481 9, /* CONF_HW_RXTX_RATE_36 */
4482 8, /* CONF_HW_RXTX_RATE_24 */
4483
4484 /* TI-specific rate */
4485 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4486
4487 7, /* CONF_HW_RXTX_RATE_18 */
4488 6, /* CONF_HW_RXTX_RATE_12 */
4489 3, /* CONF_HW_RXTX_RATE_11 */
4490 5, /* CONF_HW_RXTX_RATE_9 */
4491 4, /* CONF_HW_RXTX_RATE_6 */
4492 2, /* CONF_HW_RXTX_RATE_5_5 */
4493 1, /* CONF_HW_RXTX_RATE_2 */
4494 0 /* CONF_HW_RXTX_RATE_1 */
4495};
4496
Shahar Levie8b03a22010-10-13 16:09:39 +02004497/* 11n STA capabilities */
4498#define HW_RX_HIGHEST_RATE 72
4499
Shahar Levi00d20102010-11-08 11:20:10 +00004500#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004501 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4502 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004503 .ht_supported = true, \
4504 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4505 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4506 .mcs = { \
4507 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4508 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4509 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4510 }, \
4511}
4512
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004513/* can't be const, mac80211 writes to this */
4514static struct ieee80211_supported_band wl1271_band_2ghz = {
4515 .channels = wl1271_channels,
4516 .n_channels = ARRAY_SIZE(wl1271_channels),
4517 .bitrates = wl1271_rates,
4518 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004519 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004520};
4521
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004522/* 5 GHz data rates for WL1273 */
4523static struct ieee80211_rate wl1271_rates_5ghz[] = {
4524 { .bitrate = 60,
4525 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4526 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4527 { .bitrate = 90,
4528 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4529 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4530 { .bitrate = 120,
4531 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4532 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4533 { .bitrate = 180,
4534 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4535 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4536 { .bitrate = 240,
4537 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4538 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4539 { .bitrate = 360,
4540 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4541 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4542 { .bitrate = 480,
4543 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4544 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4545 { .bitrate = 540,
4546 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4547 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4548};
4549
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004550/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004551static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004552 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4553 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4554 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4555 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4556 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4557 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4558 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4559 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4560 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4561 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4562 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4563 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4564 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4565 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4566 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4567 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4568 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4569 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4570 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4571 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4572 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4573 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4574 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4575 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4576 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4577 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4578 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4579 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4580 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4581 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4582 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4583 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4584 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4585 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004586};
4587
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004588/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004589static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004590 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004591 7, /* CONF_HW_RXTX_RATE_MCS7 */
4592 6, /* CONF_HW_RXTX_RATE_MCS6 */
4593 5, /* CONF_HW_RXTX_RATE_MCS5 */
4594 4, /* CONF_HW_RXTX_RATE_MCS4 */
4595 3, /* CONF_HW_RXTX_RATE_MCS3 */
4596 2, /* CONF_HW_RXTX_RATE_MCS2 */
4597 1, /* CONF_HW_RXTX_RATE_MCS1 */
4598 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004599
4600 7, /* CONF_HW_RXTX_RATE_54 */
4601 6, /* CONF_HW_RXTX_RATE_48 */
4602 5, /* CONF_HW_RXTX_RATE_36 */
4603 4, /* CONF_HW_RXTX_RATE_24 */
4604
4605 /* TI-specific rate */
4606 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4607
4608 3, /* CONF_HW_RXTX_RATE_18 */
4609 2, /* CONF_HW_RXTX_RATE_12 */
4610 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4611 1, /* CONF_HW_RXTX_RATE_9 */
4612 0, /* CONF_HW_RXTX_RATE_6 */
4613 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4614 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4615 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4616};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004617
4618static struct ieee80211_supported_band wl1271_band_5ghz = {
4619 .channels = wl1271_channels_5ghz,
4620 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4621 .bitrates = wl1271_rates_5ghz,
4622 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004623 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004624};
4625
Tobias Klausera0ea9492010-05-20 10:38:11 +02004626static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004627 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4628 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4629};
4630
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004631static const struct ieee80211_ops wl1271_ops = {
4632 .start = wl1271_op_start,
4633 .stop = wl1271_op_stop,
4634 .add_interface = wl1271_op_add_interface,
4635 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004636 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004637#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004638 .suspend = wl1271_op_suspend,
4639 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004640#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004641 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004642 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004643 .configure_filter = wl1271_op_configure_filter,
4644 .tx = wl1271_op_tx,
4645 .set_key = wl1271_op_set_key,
4646 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004647 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004648 .sched_scan_start = wl1271_op_sched_scan_start,
4649 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004650 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004651 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004652 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004653 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004654 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004655 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004656 .sta_add = wl1271_op_sta_add,
4657 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004658 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004659 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004660 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004661 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004662 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004663};
4664
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004665
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004666u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004667{
4668 u8 idx;
4669
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004670 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004671
4672 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4673 wl1271_error("Illegal RX rate from HW: %d", rate);
4674 return 0;
4675 }
4676
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004677 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004678 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4679 wl1271_error("Unsupported RX rate from HW: %d", rate);
4680 return 0;
4681 }
4682
4683 return idx;
4684}
4685
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004686static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4687 struct device_attribute *attr,
4688 char *buf)
4689{
4690 struct wl1271 *wl = dev_get_drvdata(dev);
4691 ssize_t len;
4692
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004693 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004694
4695 mutex_lock(&wl->mutex);
4696 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4697 wl->sg_enabled);
4698 mutex_unlock(&wl->mutex);
4699
4700 return len;
4701
4702}
4703
4704static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4705 struct device_attribute *attr,
4706 const char *buf, size_t count)
4707{
4708 struct wl1271 *wl = dev_get_drvdata(dev);
4709 unsigned long res;
4710 int ret;
4711
Luciano Coelho6277ed62011-04-01 17:49:54 +03004712 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004713 if (ret < 0) {
4714 wl1271_warning("incorrect value written to bt_coex_mode");
4715 return count;
4716 }
4717
4718 mutex_lock(&wl->mutex);
4719
4720 res = !!res;
4721
4722 if (res == wl->sg_enabled)
4723 goto out;
4724
4725 wl->sg_enabled = res;
4726
4727 if (wl->state == WL1271_STATE_OFF)
4728 goto out;
4729
Ido Yariva6208652011-03-01 15:14:41 +02004730 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004731 if (ret < 0)
4732 goto out;
4733
4734 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4735 wl1271_ps_elp_sleep(wl);
4736
4737 out:
4738 mutex_unlock(&wl->mutex);
4739 return count;
4740}
4741
4742static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4743 wl1271_sysfs_show_bt_coex_state,
4744 wl1271_sysfs_store_bt_coex_state);
4745
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004746static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4747 struct device_attribute *attr,
4748 char *buf)
4749{
4750 struct wl1271 *wl = dev_get_drvdata(dev);
4751 ssize_t len;
4752
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004753 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004754
4755 mutex_lock(&wl->mutex);
4756 if (wl->hw_pg_ver >= 0)
4757 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4758 else
4759 len = snprintf(buf, len, "n/a\n");
4760 mutex_unlock(&wl->mutex);
4761
4762 return len;
4763}
4764
Gery Kahn6f07b722011-07-18 14:21:49 +03004765static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004766 wl1271_sysfs_show_hw_pg_ver, NULL);
4767
Ido Yariv95dac04f2011-06-06 14:57:06 +03004768static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4769 struct bin_attribute *bin_attr,
4770 char *buffer, loff_t pos, size_t count)
4771{
4772 struct device *dev = container_of(kobj, struct device, kobj);
4773 struct wl1271 *wl = dev_get_drvdata(dev);
4774 ssize_t len;
4775 int ret;
4776
4777 ret = mutex_lock_interruptible(&wl->mutex);
4778 if (ret < 0)
4779 return -ERESTARTSYS;
4780
4781 /* Let only one thread read the log at a time, blocking others */
4782 while (wl->fwlog_size == 0) {
4783 DEFINE_WAIT(wait);
4784
4785 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4786 &wait,
4787 TASK_INTERRUPTIBLE);
4788
4789 if (wl->fwlog_size != 0) {
4790 finish_wait(&wl->fwlog_waitq, &wait);
4791 break;
4792 }
4793
4794 mutex_unlock(&wl->mutex);
4795
4796 schedule();
4797 finish_wait(&wl->fwlog_waitq, &wait);
4798
4799 if (signal_pending(current))
4800 return -ERESTARTSYS;
4801
4802 ret = mutex_lock_interruptible(&wl->mutex);
4803 if (ret < 0)
4804 return -ERESTARTSYS;
4805 }
4806
4807 /* Check if the fwlog is still valid */
4808 if (wl->fwlog_size < 0) {
4809 mutex_unlock(&wl->mutex);
4810 return 0;
4811 }
4812
4813 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4814 len = min(count, (size_t)wl->fwlog_size);
4815 wl->fwlog_size -= len;
4816 memcpy(buffer, wl->fwlog, len);
4817
4818 /* Make room for new messages */
4819 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4820
4821 mutex_unlock(&wl->mutex);
4822
4823 return len;
4824}
4825
4826static struct bin_attribute fwlog_attr = {
4827 .attr = {.name = "fwlog", .mode = S_IRUSR},
4828 .read = wl1271_sysfs_read_fwlog,
4829};
4830
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004831static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004832{
4833 int ret;
4834
4835 if (wl->mac80211_registered)
4836 return 0;
4837
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004838 ret = wl1271_fetch_nvs(wl);
4839 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004840 /* NOTE: The wl->nvs->nvs element must be first, in
4841 * order to simplify the casting, we assume it is at
4842 * the beginning of the wl->nvs structure.
4843 */
4844 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004845
4846 wl->mac_addr[0] = nvs_ptr[11];
4847 wl->mac_addr[1] = nvs_ptr[10];
4848 wl->mac_addr[2] = nvs_ptr[6];
4849 wl->mac_addr[3] = nvs_ptr[5];
4850 wl->mac_addr[4] = nvs_ptr[4];
4851 wl->mac_addr[5] = nvs_ptr[3];
4852 }
4853
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004854 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4855
4856 ret = ieee80211_register_hw(wl->hw);
4857 if (ret < 0) {
4858 wl1271_error("unable to register mac80211 hw: %d", ret);
4859 return ret;
4860 }
4861
4862 wl->mac80211_registered = true;
4863
Eliad Pellerd60080a2010-11-24 12:53:16 +02004864 wl1271_debugfs_init(wl);
4865
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004866 register_netdevice_notifier(&wl1271_dev_notifier);
4867
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004868 wl1271_notice("loaded");
4869
4870 return 0;
4871}
4872
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004873static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004874{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004875 if (wl->state == WL1271_STATE_PLT)
4876 __wl1271_plt_stop(wl);
4877
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004878 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004879 ieee80211_unregister_hw(wl->hw);
4880 wl->mac80211_registered = false;
4881
4882}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004883
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004884static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004885{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004886 static const u32 cipher_suites[] = {
4887 WLAN_CIPHER_SUITE_WEP40,
4888 WLAN_CIPHER_SUITE_WEP104,
4889 WLAN_CIPHER_SUITE_TKIP,
4890 WLAN_CIPHER_SUITE_CCMP,
4891 WL1271_CIPHER_SUITE_GEM,
4892 };
4893
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004894 /* The tx descriptor buffer and the TKIP space. */
4895 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4896 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004897
4898 /* unit us */
4899 /* FIXME: find a proper value */
4900 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004901 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004902
4903 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004904 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004905 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004906 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004907 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004908 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004909 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004910 IEEE80211_HW_AP_LINK_PS |
4911 IEEE80211_HW_AMPDU_AGGREGATION |
4912 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004913
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004914 wl->hw->wiphy->cipher_suites = cipher_suites;
4915 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4916
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004917 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004918 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4919 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004920 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004921 wl->hw->wiphy->max_sched_scan_ssids = 16;
4922 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004923 /*
4924 * Maximum length of elements in scanning probe request templates
4925 * should be the maximum length possible for a template, without
4926 * the IEEE80211 header of the template
4927 */
Eliad Peller154037d2011-08-14 13:17:12 +03004928 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004929 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004930
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004931 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4932 sizeof(struct ieee80211_header);
4933
Eliad Peller1ec23f72011-08-25 14:26:54 +03004934 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4935
Luciano Coelho4a31c112011-03-21 23:16:14 +02004936 /* make sure all our channels fit in the scanned_ch bitmask */
4937 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4938 ARRAY_SIZE(wl1271_channels_5ghz) >
4939 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004940 /*
4941 * We keep local copies of the band structs because we need to
4942 * modify them on a per-device basis.
4943 */
4944 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4945 sizeof(wl1271_band_2ghz));
4946 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4947 sizeof(wl1271_band_5ghz));
4948
4949 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4950 &wl->bands[IEEE80211_BAND_2GHZ];
4951 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4952 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004953
Kalle Valo12bd8942010-03-18 12:26:33 +02004954 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004955 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004956
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004957 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4958
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02004959 /* the FW answers probe-requests in AP-mode */
4960 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
4961 wl->hw->wiphy->probe_resp_offload =
4962 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
4963 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
4964 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
4965
Felipe Balbia390e852011-10-06 10:07:44 +03004966 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004967
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004968 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004969 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004970
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004971 wl->hw->max_rx_aggregation_subframes = 8;
4972
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004973 return 0;
4974}
4975
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004976#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004977
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004978static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004979{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004980 struct ieee80211_hw *hw;
4981 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004982 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004983 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004984
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004985 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004986
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004987 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4988 if (!hw) {
4989 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004990 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004991 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004992 }
4993
4994 wl = hw->priv;
4995 memset(wl, 0, sizeof(*wl));
4996
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004997 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02004998 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004999
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005000 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005001
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005002 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005003 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005004 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5005
Ido Yariva6208652011-03-01 15:14:41 +02005006 skb_queue_head_init(&wl->deferred_rx_queue);
5007 skb_queue_head_init(&wl->deferred_tx_queue);
5008
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005009 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005010 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005011 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5012 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5013 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005014
Eliad Peller92ef8962011-06-07 12:50:46 +03005015 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5016 if (!wl->freezable_wq) {
5017 ret = -ENOMEM;
5018 goto err_hw;
5019 }
5020
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005021 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005022 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005023 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005024 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005025 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005026 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005027 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005028 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005029 wl->ap_ps_map = 0;
5030 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005031 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005032 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005033 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005034 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005035 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005036 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005037 wl->fwlog_size = 0;
5038 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005039
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005040 /* The system link is always allocated */
5041 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5042
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005043 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005044 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005045 wl->tx_frames[i] = NULL;
5046
5047 spin_lock_init(&wl->wl_lock);
5048
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005049 wl->state = WL1271_STATE_OFF;
5050 mutex_init(&wl->mutex);
5051
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005052 /* Apply default driver configuration. */
5053 wl1271_conf_init(wl);
5054
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005055 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5056 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5057 if (!wl->aggr_buf) {
5058 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005059 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005060 }
5061
Ido Yariv990f5de2011-03-31 10:06:59 +02005062 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5063 if (!wl->dummy_packet) {
5064 ret = -ENOMEM;
5065 goto err_aggr;
5066 }
5067
Ido Yariv95dac04f2011-06-06 14:57:06 +03005068 /* Allocate one page for the FW log */
5069 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5070 if (!wl->fwlog) {
5071 ret = -ENOMEM;
5072 goto err_dummy_packet;
5073 }
5074
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005075 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005076
Ido Yariv990f5de2011-03-31 10:06:59 +02005077err_dummy_packet:
5078 dev_kfree_skb(wl->dummy_packet);
5079
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005080err_aggr:
5081 free_pages((unsigned long)wl->aggr_buf, order);
5082
Eliad Peller92ef8962011-06-07 12:50:46 +03005083err_wq:
5084 destroy_workqueue(wl->freezable_wq);
5085
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005086err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005087 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005088 ieee80211_free_hw(hw);
5089
5090err_hw_alloc:
5091
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005092 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005093}
5094
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005095static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005096{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005097 /* Unblock any fwlog readers */
5098 mutex_lock(&wl->mutex);
5099 wl->fwlog_size = -1;
5100 wake_up_interruptible_all(&wl->fwlog_waitq);
5101 mutex_unlock(&wl->mutex);
5102
Felipe Balbif79f8902011-10-06 13:05:25 +03005103 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005104
Felipe Balbif79f8902011-10-06 13:05:25 +03005105 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005106
Felipe Balbif79f8902011-10-06 13:05:25 +03005107 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005108 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005109 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005110 free_pages((unsigned long)wl->aggr_buf,
5111 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005112
5113 wl1271_debugfs_exit(wl);
5114
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005115 vfree(wl->fw);
5116 wl->fw = NULL;
5117 kfree(wl->nvs);
5118 wl->nvs = NULL;
5119
5120 kfree(wl->fw_status);
5121 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005122 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005123
5124 ieee80211_free_hw(wl->hw);
5125
5126 return 0;
5127}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005128
Felipe Balbia390e852011-10-06 10:07:44 +03005129static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5130{
5131 struct wl1271 *wl = cookie;
5132 unsigned long flags;
5133
5134 wl1271_debug(DEBUG_IRQ, "IRQ");
5135
5136 /* complete the ELP completion */
5137 spin_lock_irqsave(&wl->wl_lock, flags);
5138 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5139 if (wl->elp_compl) {
5140 complete(wl->elp_compl);
5141 wl->elp_compl = NULL;
5142 }
5143
5144 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5145 /* don't enqueue a work right now. mark it as pending */
5146 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5147 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5148 disable_irq_nosync(wl->irq);
5149 pm_wakeup_event(wl->dev, 0);
5150 spin_unlock_irqrestore(&wl->wl_lock, flags);
5151 return IRQ_HANDLED;
5152 }
5153 spin_unlock_irqrestore(&wl->wl_lock, flags);
5154
5155 return IRQ_WAKE_THREAD;
5156}
5157
Felipe Balbice2a2172011-10-05 14:12:55 +03005158static int __devinit wl12xx_probe(struct platform_device *pdev)
5159{
Felipe Balbia390e852011-10-06 10:07:44 +03005160 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5161 struct ieee80211_hw *hw;
5162 struct wl1271 *wl;
5163 unsigned long irqflags;
5164 int ret = -ENODEV;
5165
5166 hw = wl1271_alloc_hw();
5167 if (IS_ERR(hw)) {
5168 wl1271_error("can't allocate hw");
5169 ret = PTR_ERR(hw);
5170 goto out;
5171 }
5172
5173 wl = hw->priv;
5174 wl->irq = platform_get_irq(pdev, 0);
5175 wl->ref_clock = pdata->board_ref_clock;
5176 wl->tcxo_clock = pdata->board_tcxo_clock;
5177 wl->platform_quirks = pdata->platform_quirks;
5178 wl->set_power = pdata->set_power;
5179 wl->dev = &pdev->dev;
5180 wl->if_ops = pdata->ops;
5181
5182 platform_set_drvdata(pdev, wl);
5183
5184 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5185 irqflags = IRQF_TRIGGER_RISING;
5186 else
5187 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5188
5189 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5190 irqflags,
5191 pdev->name, wl);
5192 if (ret < 0) {
5193 wl1271_error("request_irq() failed: %d", ret);
5194 goto out_free_hw;
5195 }
5196
5197 ret = enable_irq_wake(wl->irq);
5198 if (!ret) {
5199 wl->irq_wake_enabled = true;
5200 device_init_wakeup(wl->dev, 1);
5201 if (pdata->pwr_in_suspend)
5202 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5203
5204 }
5205 disable_irq(wl->irq);
5206
5207 ret = wl1271_init_ieee80211(wl);
5208 if (ret)
5209 goto out_irq;
5210
5211 ret = wl1271_register_hw(wl);
5212 if (ret)
5213 goto out_irq;
5214
Felipe Balbif79f8902011-10-06 13:05:25 +03005215 /* Create sysfs file to control bt coex state */
5216 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5217 if (ret < 0) {
5218 wl1271_error("failed to create sysfs file bt_coex_state");
5219 goto out_irq;
5220 }
5221
5222 /* Create sysfs file to get HW PG version */
5223 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5224 if (ret < 0) {
5225 wl1271_error("failed to create sysfs file hw_pg_ver");
5226 goto out_bt_coex_state;
5227 }
5228
5229 /* Create sysfs file for the FW log */
5230 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5231 if (ret < 0) {
5232 wl1271_error("failed to create sysfs file fwlog");
5233 goto out_hw_pg_ver;
5234 }
5235
Felipe Balbice2a2172011-10-05 14:12:55 +03005236 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005237
Felipe Balbif79f8902011-10-06 13:05:25 +03005238out_hw_pg_ver:
5239 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5240
5241out_bt_coex_state:
5242 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5243
Felipe Balbia390e852011-10-06 10:07:44 +03005244out_irq:
5245 free_irq(wl->irq, wl);
5246
5247out_free_hw:
5248 wl1271_free_hw(wl);
5249
5250out:
5251 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005252}
5253
5254static int __devexit wl12xx_remove(struct platform_device *pdev)
5255{
Felipe Balbia390e852011-10-06 10:07:44 +03005256 struct wl1271 *wl = platform_get_drvdata(pdev);
5257
5258 if (wl->irq_wake_enabled) {
5259 device_init_wakeup(wl->dev, 0);
5260 disable_irq_wake(wl->irq);
5261 }
5262 wl1271_unregister_hw(wl);
5263 free_irq(wl->irq, wl);
5264 wl1271_free_hw(wl);
5265
Felipe Balbice2a2172011-10-05 14:12:55 +03005266 return 0;
5267}
5268
5269static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005270 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005271 { } /* Terminating Entry */
5272};
5273MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5274
5275static struct platform_driver wl12xx_driver = {
5276 .probe = wl12xx_probe,
5277 .remove = __devexit_p(wl12xx_remove),
5278 .id_table = wl12xx_id_table,
5279 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005280 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005281 .owner = THIS_MODULE,
5282 }
5283};
5284
5285static int __init wl12xx_init(void)
5286{
5287 return platform_driver_register(&wl12xx_driver);
5288}
5289module_init(wl12xx_init);
5290
5291static void __exit wl12xx_exit(void)
5292{
5293 platform_driver_unregister(&wl12xx_driver);
5294}
5295module_exit(wl12xx_exit);
5296
Guy Eilam491bbd62011-01-12 10:33:29 +01005297u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005298EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005299module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005300MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5301
Ido Yariv95dac04f2011-06-06 14:57:06 +03005302module_param_named(fwlog, fwlog_param, charp, 0);
5303MODULE_PARM_DESC(keymap,
5304 "FW logger options: continuous, ondemand, dbgpins or disable");
5305
Eliad Peller2a5bff02011-08-25 18:10:59 +03005306module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5307MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5308
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005309MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005310MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005311MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");