blob: f2a958c9537a347483a11a81c936f0f776508b80 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Felipe Balbia390e852011-10-06 10:07:44 +030035#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "wl12xx.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030038#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030039#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000040#include "reg.h"
41#include "io.h"
42#include "event.h"
43#include "tx.h"
44#include "rx.h"
45#include "ps.h"
46#include "init.h"
47#include "debugfs.h"
48#include "cmd.h"
49#include "boot.h"
50#include "testmode.h"
51#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030052
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020053#define WL1271_BOOT_RETRIES 3
54
Juuso Oikarinen8a080482009-10-13 12:47:44 +030055static struct conf_drv_settings default_conf = {
56 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030057 .params = {
58 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
61 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
62 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
64 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
65 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
66 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
68 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
69 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
70 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
71 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
73 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
74 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
75 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
76 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
77 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
78 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
79 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
82 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
83 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
84 /* active scan params */
85 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
86 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
87 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
88 /* passive scan params */
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
91 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
92 /* passive scan in dual antenna params */
93 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
94 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
95 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
96 /* general params */
97 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
98 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
99 [CONF_SG_BEACON_MISS_PERCENT] = 60,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_RXT] = 1200,
102 [CONF_SG_TXT] = 1000,
103 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
104 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
105 [CONF_SG_HV3_MAX_SERVED] = 6,
106 [CONF_SG_PS_POLL_TIMEOUT] = 10,
107 [CONF_SG_UPSD_TIMEOUT] = 10,
108 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
109 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
110 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
111 /* AP params */
112 [CONF_AP_BEACON_MISS_TX] = 3,
113 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
114 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
115 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
116 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
117 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300118 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200119 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300120 },
121 .rx = {
122 .rx_msdu_life_time = 512000,
123 .packet_detection_threshold = 0,
124 .ps_poll_timeout = 15,
125 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300126 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200127 .rx_cca_threshold = 0,
128 .irq_blk_threshold = 0xFFFF,
129 .irq_pkt_threshold = 0,
130 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300131 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
132 },
133 .tx = {
134 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200135 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300136 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300137 .short_retry_limit = 10,
138 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200139 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300140 },
141 .ac_conf_count = 4,
142 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200143 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300144 .ac = CONF_TX_AC_BE,
145 .cw_min = 15,
146 .cw_max = 63,
147 .aifsn = 3,
148 .tx_op_limit = 0,
149 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200150 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300151 .ac = CONF_TX_AC_BK,
152 .cw_min = 15,
153 .cw_max = 63,
154 .aifsn = 7,
155 .tx_op_limit = 0,
156 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200157 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300158 .ac = CONF_TX_AC_VI,
159 .cw_min = 15,
160 .cw_max = 63,
161 .aifsn = CONF_TX_AIFS_PIFS,
162 .tx_op_limit = 3008,
163 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200164 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300165 .ac = CONF_TX_AC_VO,
166 .cw_min = 15,
167 .cw_max = 63,
168 .aifsn = CONF_TX_AIFS_PIFS,
169 .tx_op_limit = 1504,
170 },
171 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300172 .max_tx_retries = 100,
173 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300175 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200176 [CONF_TX_AC_BE] = {
177 .queue_id = CONF_TX_AC_BE,
178 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300179 .tsid = CONF_TX_AC_BE,
180 .ps_scheme = CONF_PS_SCHEME_LEGACY,
181 .ack_policy = CONF_ACK_POLICY_LEGACY,
182 .apsd_conf = {0, 0},
183 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200184 [CONF_TX_AC_BK] = {
185 .queue_id = CONF_TX_AC_BK,
186 .channel_type = CONF_CHANNEL_TYPE_EDCF,
187 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300188 .ps_scheme = CONF_PS_SCHEME_LEGACY,
189 .ack_policy = CONF_ACK_POLICY_LEGACY,
190 .apsd_conf = {0, 0},
191 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200192 [CONF_TX_AC_VI] = {
193 .queue_id = CONF_TX_AC_VI,
194 .channel_type = CONF_CHANNEL_TYPE_EDCF,
195 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .ps_scheme = CONF_PS_SCHEME_LEGACY,
197 .ack_policy = CONF_ACK_POLICY_LEGACY,
198 .apsd_conf = {0, 0},
199 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200200 [CONF_TX_AC_VO] = {
201 .queue_id = CONF_TX_AC_VO,
202 .channel_type = CONF_CHANNEL_TYPE_EDCF,
203 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300204 .ps_scheme = CONF_PS_SCHEME_LEGACY,
205 .ack_policy = CONF_ACK_POLICY_LEGACY,
206 .apsd_conf = {0, 0},
207 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300208 },
209 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200210 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300211 .tx_compl_threshold = 4,
212 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
213 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200214 .tmpl_short_retry_limit = 10,
215 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300216 },
217 .conn = {
218 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300219 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300221 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300222 .bcn_filt_ie = {
223 [0] = {
224 .ie = WLAN_EID_CHANNEL_SWITCH,
225 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300226 },
227 [1] = {
228 .ie = WLAN_EID_HT_INFORMATION,
229 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
230 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200232 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 .bss_lose_timeout = 100,
234 .beacon_rx_timeout = 10000,
235 .broadcast_timeout = 20000,
236 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300237 .ps_poll_threshold = 10,
238 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300239 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e02011-03-14 18:53:10 +0200240 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300241 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300242 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200243 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300244 .keep_alive_interval = 55000,
245 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300246 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200247 .itrim = {
248 .enable = false,
249 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200250 },
251 .pm_config = {
252 .host_clk_settling_time = 5000,
253 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 },
255 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300256 .trigger_pacing = 1,
257 .avg_weight_rssi_beacon = 20,
258 .avg_weight_rssi_data = 10,
259 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100260 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200261 },
262 .scan = {
263 .min_dwell_time_active = 7500,
264 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100265 .min_dwell_time_passive = 100000,
266 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200267 .num_probe_reqs = 2,
268 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300269 .sched_scan = {
270 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300271 .min_dwell_time_active = 30,
272 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300274 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300275 .num_probe_reqs = 2,
276 .rssi_threshold = -90,
277 .snr_threshold = 0,
278 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200279 .rf = {
280 .tx_per_channel_power_compensation_2 = {
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 },
283 .tx_per_channel_power_compensation_5 = {
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 },
288 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300290 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100291 .tx_ba_win_size = 64,
292 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300293 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100294 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200295 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200296 .num_stations = 1,
297 .ssid_profiles = 1,
298 .rx_block_num = 70,
299 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300300 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200301 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200302 .min_req_rx_blocks = 22,
303 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200304 },
305 .mem_wl128x = {
306 .num_stations = 1,
307 .ssid_profiles = 1,
308 .rx_block_num = 40,
309 .tx_min_block_num = 40,
310 .dynamic_memory = 1,
311 .min_req_tx_blocks = 45,
312 .min_req_rx_blocks = 22,
313 .tx_min = 27,
314 },
Shahar Leviff868432011-04-11 15:41:46 +0300315 .fm_coex = {
316 .enable = true,
317 .swallow_period = 5,
318 .n_divider_fref_set_1 = 0xff, /* default */
319 .n_divider_fref_set_2 = 12,
320 .m_divider_fref_set_1 = 148,
321 .m_divider_fref_set_2 = 0xffff, /* default */
322 .coex_pll_stabilization_time = 0xffffffff, /* default */
323 .ldo_stabilization_time = 0xffff, /* default */
324 .fm_disturbed_band_margin = 0xff, /* default */
325 .swallow_clk_diff = 0xff, /* default */
326 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300327 .rx_streaming = {
328 .duration = 150,
329 .queues = 0x1,
330 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300331 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300332 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300333 .fwlog = {
334 .mode = WL12XX_FWLOG_ON_DEMAND,
335 .mem_blocks = 2,
336 .severity = 0,
337 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
338 .output = WL12XX_FWLOG_OUTPUT_HOST,
339 .threshold = 0,
340 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300341 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300342 .rate = {
343 .rate_retry_score = 32000,
344 .per_add = 8192,
345 .per_th1 = 2048,
346 .per_th2 = 4096,
347 .max_per = 8100,
348 .inverse_curiosity_factor = 5,
349 .tx_fail_low_th = 4,
350 .tx_fail_high_th = 10,
351 .per_alpha_shift = 4,
352 .per_add_shift = 13,
353 .per_beta1_shift = 10,
354 .per_beta2_shift = 8,
355 .rate_check_up = 2,
356 .rate_check_down = 12,
357 .rate_retry_policy = {
358 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00,
361 },
362 },
Eliad Peller94877752011-08-28 15:11:56 +0300363 .hangover = {
364 .recover_time = 0,
365 .hangover_period = 20,
366 .dynamic_mode = 1,
367 .early_termination_mode = 1,
368 .max_period = 20,
369 .min_period = 1,
370 .increase_delta = 1,
371 .decrease_delta = 2,
372 .quiet_time = 4,
373 .increase_time = 1,
374 .window_size = 16,
375 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300376};
377
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300379static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300380
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300381static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c82011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Yarivbaacb9ae2011-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 Yarivbaacb9ae2011-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 Yarivbaacb9ae2011-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 Pellerba8447f62011-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 Yarivbaacb9ae2011-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 Nemtsov04b4d69c2011-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 Pellerba8447f62011-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 Peller536129c82011-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 Peller536129c82011-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 Peller536129c82011-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 Peller536129c82011-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 Peller536129c82011-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 Peller536129c82011-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 Peller876272142011-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 Peller536129c82011-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 Peller536129c82011-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 Peller876272142011-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 Peller536129c82011-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 Peller536129c82011-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 Peller536129c82011-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 Peller876272142011-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 Coelhod6e19d132009-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 Peller536129c82011-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 Peller536129c82011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Pirko22bedad32010-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 Pirko22bedad32010-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 Pirko22bedad32010-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 Pirko22bedad32010-04-01 21:22:57 +00002641 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002642 fp->mc_list_length++;
Jiri Pirko22bedad32010-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 Peller536129c82011-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 Peller536129c82011-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 Peller536129c82011-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 Peller536129c82011-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 Peller536129c82011-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 Peller536129c82011-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 Peller536129c82011-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
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003111 if (wl->state == WL1271_STATE_OFF) {
3112 ret = -EAGAIN;
3113 goto out;
3114 }
3115
Luciano Coelho33c2c062011-05-10 14:46:02 +03003116 ret = wl1271_ps_elp_wakeup(wl);
3117 if (ret < 0)
3118 goto out;
3119
Eliad Peller536129c82011-10-05 11:55:45 +02003120 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003121 if (ret < 0)
3122 goto out_sleep;
3123
Eliad Peller536129c82011-10-05 11:55:45 +02003124 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003125 if (ret < 0)
3126 goto out_sleep;
3127
3128 wl->sched_scanning = true;
3129
3130out_sleep:
3131 wl1271_ps_elp_sleep(wl);
3132out:
3133 mutex_unlock(&wl->mutex);
3134 return ret;
3135}
3136
3137static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3138 struct ieee80211_vif *vif)
3139{
3140 struct wl1271 *wl = hw->priv;
3141 int ret;
3142
3143 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3144
3145 mutex_lock(&wl->mutex);
3146
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003147 if (wl->state == WL1271_STATE_OFF)
3148 goto out;
3149
Luciano Coelho33c2c062011-05-10 14:46:02 +03003150 ret = wl1271_ps_elp_wakeup(wl);
3151 if (ret < 0)
3152 goto out;
3153
3154 wl1271_scan_sched_scan_stop(wl);
3155
3156 wl1271_ps_elp_sleep(wl);
3157out:
3158 mutex_unlock(&wl->mutex);
3159}
3160
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003161static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3162{
3163 struct wl1271 *wl = hw->priv;
3164 int ret = 0;
3165
3166 mutex_lock(&wl->mutex);
3167
3168 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3169 ret = -EAGAIN;
3170 goto out;
3171 }
3172
Ido Yariva6208652011-03-01 15:14:41 +02003173 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003174 if (ret < 0)
3175 goto out;
3176
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003177 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003178 if (ret < 0)
3179 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3180
3181 wl1271_ps_elp_sleep(wl);
3182
3183out:
3184 mutex_unlock(&wl->mutex);
3185
3186 return ret;
3187}
3188
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003189static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3190{
3191 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003192 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003193 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003194
3195 mutex_lock(&wl->mutex);
3196
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003197 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3198 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003199 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003200 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003201
Ido Yariva6208652011-03-01 15:14:41 +02003202 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003203 if (ret < 0)
3204 goto out;
3205
Eliad Peller6e8cd332011-10-10 10:13:13 +02003206 wl12xx_for_each_wlvif(wl, wlvif) {
3207 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3208 if (ret < 0)
3209 wl1271_warning("set rts threshold failed: %d", ret);
3210 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003211 wl1271_ps_elp_sleep(wl);
3212
3213out:
3214 mutex_unlock(&wl->mutex);
3215
3216 return ret;
3217}
3218
Eliad Peller1fe9f162011-10-05 11:55:48 +02003219static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003220 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003221{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003222 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003223 u8 ssid_len;
3224 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3225 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003226
Eliad Peller889cb362011-05-01 09:56:45 +03003227 if (!ptr) {
3228 wl1271_error("No SSID in IEs!");
3229 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003230 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003231
Eliad Peller889cb362011-05-01 09:56:45 +03003232 ssid_len = ptr[1];
3233 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3234 wl1271_error("SSID is too long!");
3235 return -EINVAL;
3236 }
3237
Eliad Peller1fe9f162011-10-05 11:55:48 +02003238 wlvif->ssid_len = ssid_len;
3239 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003240 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003241}
3242
Eliad Pellerd48055d2011-09-15 12:07:04 +03003243static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3244{
3245 int len;
3246 const u8 *next, *end = skb->data + skb->len;
3247 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3248 skb->len - ieoffset);
3249 if (!ie)
3250 return;
3251 len = ie[1] + 2;
3252 next = ie + len;
3253 memmove(ie, next, end - next);
3254 skb_trim(skb, skb->len - len);
3255}
3256
Eliad Peller26b4bf22011-09-15 12:07:05 +03003257static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3258 unsigned int oui, u8 oui_type,
3259 int ieoffset)
3260{
3261 int len;
3262 const u8 *next, *end = skb->data + skb->len;
3263 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3264 skb->data + ieoffset,
3265 skb->len - ieoffset);
3266 if (!ie)
3267 return;
3268 len = ie[1] + 2;
3269 next = ie + len;
3270 memmove(ie, next, end - next);
3271 skb_trim(skb, skb->len - len);
3272}
3273
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003274static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3275 struct ieee80211_vif *vif)
Arik Nemtsov560f002412011-11-08 18:46:54 +02003276{
3277 struct sk_buff *skb;
3278 int ret;
3279
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003280 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003281 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003282 return -EOPNOTSUPP;
Arik Nemtsov560f002412011-11-08 18:46:54 +02003283
3284 ret = wl1271_cmd_template_set(wl,
3285 CMD_TEMPL_AP_PROBE_RESPONSE,
3286 skb->data,
3287 skb->len, 0,
3288 rates);
3289
3290 dev_kfree_skb(skb);
3291 return ret;
3292}
3293
3294static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3295 struct ieee80211_vif *vif,
3296 u8 *probe_rsp_data,
3297 size_t probe_rsp_len,
3298 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003299{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003300 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3301 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003302 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3303 int ssid_ie_offset, ie_offset, templ_len;
3304 const u8 *ptr;
3305
3306 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003307 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003308 return wl1271_cmd_template_set(wl,
3309 CMD_TEMPL_AP_PROBE_RESPONSE,
3310 probe_rsp_data,
3311 probe_rsp_len, 0,
3312 rates);
3313
3314 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3315 wl1271_error("probe_rsp template too big");
3316 return -EINVAL;
3317 }
3318
3319 /* start searching from IE offset */
3320 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3321
3322 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3323 probe_rsp_len - ie_offset);
3324 if (!ptr) {
3325 wl1271_error("No SSID in beacon!");
3326 return -EINVAL;
3327 }
3328
3329 ssid_ie_offset = ptr - probe_rsp_data;
3330 ptr += (ptr[1] + 2);
3331
3332 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3333
3334 /* insert SSID from bss_conf */
3335 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3336 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3337 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3338 bss_conf->ssid, bss_conf->ssid_len);
3339 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3340
3341 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3342 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3343 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3344
3345 return wl1271_cmd_template_set(wl,
3346 CMD_TEMPL_AP_PROBE_RESPONSE,
3347 probe_rsp_templ,
3348 templ_len, 0,
3349 rates);
3350}
3351
Arik Nemtsove78a2872010-10-16 19:07:21 +02003352static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003353 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003354 struct ieee80211_bss_conf *bss_conf,
3355 u32 changed)
3356{
Eliad Peller0603d892011-10-05 11:55:51 +02003357 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003358 int ret = 0;
3359
3360 if (changed & BSS_CHANGED_ERP_SLOT) {
3361 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003362 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003363 else
Eliad Peller0603d892011-10-05 11:55:51 +02003364 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003365 if (ret < 0) {
3366 wl1271_warning("Set slot time failed %d", ret);
3367 goto out;
3368 }
3369 }
3370
3371 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3372 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003373 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003374 else
Eliad Peller0603d892011-10-05 11:55:51 +02003375 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003376 }
3377
3378 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3379 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003380 ret = wl1271_acx_cts_protect(wl, wlvif,
3381 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003382 else
Eliad Peller0603d892011-10-05 11:55:51 +02003383 ret = wl1271_acx_cts_protect(wl, wlvif,
3384 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003385 if (ret < 0) {
3386 wl1271_warning("Set ctsprotect failed %d", ret);
3387 goto out;
3388 }
3389 }
3390
3391out:
3392 return ret;
3393}
3394
3395static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3396 struct ieee80211_vif *vif,
3397 struct ieee80211_bss_conf *bss_conf,
3398 u32 changed)
3399{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003400 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c82011-10-05 11:55:45 +02003401 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003402 int ret = 0;
3403
3404 if ((changed & BSS_CHANGED_BEACON_INT)) {
3405 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3406 bss_conf->beacon_int);
3407
Eliad Peller6a899792011-10-05 11:55:58 +02003408 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003409 }
3410
Arik Nemtsov560f002412011-11-08 18:46:54 +02003411 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3412 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003413 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3414 wl1271_debug(DEBUG_AP, "probe response updated");
3415 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3416 }
Arik Nemtsov560f002412011-11-08 18:46:54 +02003417 }
3418
Arik Nemtsove78a2872010-10-16 19:07:21 +02003419 if ((changed & BSS_CHANGED_BEACON)) {
3420 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003421 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003422 int ieoffset = offsetof(struct ieee80211_mgmt,
3423 u.beacon.variable);
3424 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3425 u16 tmpl_id;
3426
Arik Nemtsov560f002412011-11-08 18:46:54 +02003427 if (!beacon) {
3428 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003429 goto out;
Arik Nemtsov560f002412011-11-08 18:46:54 +02003430 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003431
3432 wl1271_debug(DEBUG_MASTER, "beacon updated");
3433
Eliad Peller1fe9f162011-10-05 11:55:48 +02003434 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003435 if (ret < 0) {
3436 dev_kfree_skb(beacon);
3437 goto out;
3438 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003439 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003440 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3441 CMD_TEMPL_BEACON;
3442 ret = wl1271_cmd_template_set(wl, tmpl_id,
3443 beacon->data,
3444 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003445 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003446 if (ret < 0) {
3447 dev_kfree_skb(beacon);
3448 goto out;
3449 }
3450
Arik Nemtsov560f002412011-11-08 18:46:54 +02003451 /*
3452 * In case we already have a probe-resp beacon set explicitly
3453 * by usermode, don't use the beacon data.
3454 */
3455 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3456 goto end_bcn;
3457
Eliad Pellerd48055d2011-09-15 12:07:04 +03003458 /* remove TIM ie from probe response */
3459 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3460
Eliad Peller26b4bf22011-09-15 12:07:05 +03003461 /*
3462 * remove p2p ie from probe response.
3463 * the fw reponds to probe requests that don't include
3464 * the p2p ie. probe requests with p2p ie will be passed,
3465 * and will be responded by the supplicant (the spec
3466 * forbids including the p2p ie when responding to probe
3467 * requests that didn't include it).
3468 */
3469 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3470 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3471
Arik Nemtsove78a2872010-10-16 19:07:21 +02003472 hdr = (struct ieee80211_hdr *) beacon->data;
3473 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3474 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003475 if (is_ap)
Arik Nemtsov560f002412011-11-08 18:46:54 +02003476 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003477 beacon->data,
3478 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003479 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003480 else
3481 ret = wl1271_cmd_template_set(wl,
3482 CMD_TEMPL_PROBE_RESPONSE,
3483 beacon->data,
3484 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003485 min_rate);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003486end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003487 dev_kfree_skb(beacon);
3488 if (ret < 0)
3489 goto out;
3490 }
3491
3492out:
Arik Nemtsov560f002412011-11-08 18:46:54 +02003493 if (ret != 0)
3494 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003495 return ret;
3496}
3497
3498/* AP mode changes */
3499static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003500 struct ieee80211_vif *vif,
3501 struct ieee80211_bss_conf *bss_conf,
3502 u32 changed)
3503{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003504 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003505 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003506
Arik Nemtsove78a2872010-10-16 19:07:21 +02003507 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3508 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003509
Eliad Peller87fbcb02011-10-05 11:55:41 +02003510 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003511 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003512 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003513 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003514
Eliad Peller87fbcb02011-10-05 11:55:41 +02003515 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003516 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003517 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003518 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003519 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003520
Eliad Peller784f6942011-10-05 11:55:39 +02003521 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003522 if (ret < 0)
3523 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003524 }
3525
Arik Nemtsove78a2872010-10-16 19:07:21 +02003526 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3527 if (ret < 0)
3528 goto out;
3529
3530 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3531 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003532 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003533 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003534 if (ret < 0)
3535 goto out;
3536
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003537 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003538 if (ret < 0)
3539 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003540
Eliad Peller53d40d02011-10-10 10:13:02 +02003541 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003542 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003543 }
3544 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003545 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003546 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003547 if (ret < 0)
3548 goto out;
3549
Eliad Peller53d40d02011-10-10 10:13:02 +02003550 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003551 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3552 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003553 wl1271_debug(DEBUG_AP, "stopped AP");
3554 }
3555 }
3556 }
3557
Eliad Peller0603d892011-10-05 11:55:51 +02003558 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003559 if (ret < 0)
3560 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003561
3562 /* Handle HT information change */
3563 if ((changed & BSS_CHANGED_HT) &&
3564 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003565 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003566 bss_conf->ht_operation_mode);
3567 if (ret < 0) {
3568 wl1271_warning("Set ht information failed %d", ret);
3569 goto out;
3570 }
3571 }
3572
Arik Nemtsove78a2872010-10-16 19:07:21 +02003573out:
3574 return;
3575}
3576
3577/* STA/IBSS mode changes */
3578static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3579 struct ieee80211_vif *vif,
3580 struct ieee80211_bss_conf *bss_conf,
3581 u32 changed)
3582{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003583 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003584 bool do_join = false, set_assoc = false;
Eliad Peller536129c82011-10-05 11:55:45 +02003585 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003586 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003587 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003588 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003589 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003590 bool sta_exists = false;
3591 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003592
3593 if (is_ibss) {
3594 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3595 changed);
3596 if (ret < 0)
3597 goto out;
3598 }
3599
Eliad Peller227e81e2011-08-14 13:17:26 +03003600 if (changed & BSS_CHANGED_IBSS) {
3601 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003602 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003603 ibss_joined = true;
3604 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003605 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3606 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003607 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003608 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003609 }
3610 }
3611 }
3612
3613 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003614 do_join = true;
3615
3616 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003617 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003618 do_join = true;
3619
Eliad Peller227e81e2011-08-14 13:17:26 +03003620 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003621 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3622 bss_conf->enable_beacon ? "enabled" : "disabled");
3623
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003624 do_join = true;
3625 }
3626
Eliad Pellerc31e4942011-10-23 08:21:55 +02003627 if (changed & BSS_CHANGED_IDLE) {
3628 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3629 if (ret < 0)
3630 wl1271_warning("idle mode change failed %d", ret);
3631 }
3632
Arik Nemtsove78a2872010-10-16 19:07:21 +02003633 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003634 bool enable = false;
3635 if (bss_conf->cqm_rssi_thold)
3636 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003637 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003638 bss_conf->cqm_rssi_thold,
3639 bss_conf->cqm_rssi_hyst);
3640 if (ret < 0)
3641 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003642 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003643 }
3644
Eliad Pellercdf09492011-10-05 11:55:44 +02003645 if (changed & BSS_CHANGED_BSSID)
3646 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003647 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003648 if (ret < 0)
3649 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003650
Eliad Peller784f6942011-10-05 11:55:39 +02003651 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003652 if (ret < 0)
3653 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003654
Eliad Pellerfa287b82010-12-26 09:27:50 +01003655 /* Need to update the BSSID (for filtering etc) */
3656 do_join = true;
3657 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003658
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003659 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3660 rcu_read_lock();
3661 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3662 if (!sta)
3663 goto sta_not_found;
3664
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003665 /* save the supp_rates of the ap */
3666 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3667 if (sta->ht_cap.ht_supported)
3668 sta_rate_set |=
3669 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003670 sta_ht_cap = sta->ht_cap;
3671 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003672
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003673sta_not_found:
3674 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003675 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003676
Arik Nemtsove78a2872010-10-16 19:07:21 +02003677 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003678 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003679 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003680 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003681 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003682 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003683
Eliad Peller74ec8392011-10-05 11:56:02 +02003684 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003685
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003686 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003687 * use basic rates from AP, and determine lowest rate
3688 * to use with control frames.
3689 */
3690 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003691 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003692 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003693 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003694 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003695 wl1271_tx_min_rate_get(wl,
3696 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003697 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003698 wlvif->rate_set =
3699 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003700 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003701 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003702 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003703 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003704 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003705
3706 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003707 * with wl1271, we don't need to update the
3708 * beacon_int and dtim_period, because the firmware
3709 * updates it by itself when the first beacon is
3710 * received after a join.
3711 */
Eliad Peller6840e372011-10-05 11:55:50 +02003712 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003713 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003714 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003715
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003716 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003717 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003718 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003719 dev_kfree_skb(wlvif->probereq);
3720 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003721 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003722 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003723 ieoffset = offsetof(struct ieee80211_mgmt,
3724 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003725 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003726
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003727 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003728 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003729 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003730 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003731 } else {
3732 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003733 bool was_assoc =
Eliad Pellerba8447f62011-10-10 10:13:00 +02003734 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3735 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003736 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003737 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3738 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003739 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003740
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003741 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003742 dev_kfree_skb(wlvif->probereq);
3743 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003744
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003745 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003746 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003747
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003748 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003749 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003750 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003751 wl1271_tx_min_rate_get(wl,
3752 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003753 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003754 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003755 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003756
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003757 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003758 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003759
3760 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003761 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003762 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003763 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003764
3765 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003766 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003767 u32 conf_flags = wl->hw->conf.flags;
3768 /*
3769 * we might have to disable roc, if there was
3770 * no IF_OPER_UP notification.
3771 */
3772 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003773 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003774 if (ret < 0)
3775 goto out;
3776 }
3777 /*
3778 * (we also need to disable roc in case of
3779 * roaming on the same channel. until we will
3780 * have a better flow...)
3781 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003782 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3783 ret = wl12xx_croc(wl,
3784 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003785 if (ret < 0)
3786 goto out;
3787 }
3788
Eliad Peller0603d892011-10-05 11:55:51 +02003789 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003790 if (!(conf_flags & IEEE80211_CONF_IDLE))
3791 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003792 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003793 }
3794 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003795
Eliad Pellerd192d262011-05-24 14:33:08 +03003796 if (changed & BSS_CHANGED_IBSS) {
3797 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3798 bss_conf->ibss_joined);
3799
3800 if (bss_conf->ibss_joined) {
3801 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003802 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003803 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003804 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003805 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003806 wl1271_tx_min_rate_get(wl,
3807 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003808
Shahar Levi06b660e2011-09-05 13:54:36 +03003809 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003810 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3811 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003812 if (ret < 0)
3813 goto out;
3814 }
3815 }
3816
Eliad Peller0603d892011-10-05 11:55:51 +02003817 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003818 if (ret < 0)
3819 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003820
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003821 if (changed & BSS_CHANGED_ARP_FILTER) {
3822 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c82011-10-05 11:55:45 +02003823 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003824
Eliad Pellerc5312772010-12-09 11:31:27 +02003825 if (bss_conf->arp_addr_cnt == 1 &&
3826 bss_conf->arp_filter_enabled) {
3827 /*
3828 * The template should have been configured only upon
3829 * association. however, it seems that the correct ip
3830 * isn't being set (when sending), so we have to
3831 * reconfigure the template upon every ip change.
3832 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003833 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003834 if (ret < 0) {
3835 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003836 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003837 }
3838
Eliad Peller0603d892011-10-05 11:55:51 +02003839 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003840 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003841 addr);
3842 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003843 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003844
3845 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003846 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003847 }
3848
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003849 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003850 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003851 if (ret < 0) {
3852 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003853 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003854 }
Eliad Peller251c1772011-08-14 13:17:17 +03003855
3856 /* ROC until connected (after EAPOL exchange) */
3857 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003858 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003859 if (ret < 0)
3860 goto out;
3861
Eliad Pellerba8447f62011-10-10 10:13:00 +02003862 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003863 ieee80211_get_operstate(vif));
3864 }
3865 /*
3866 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003867 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003868 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003869 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003870 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003871 if (ret < 0)
3872 goto out;
3873 }
Eliad Peller05dba352011-08-23 16:37:01 +03003874
3875 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003876 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3877 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003878 enum wl1271_cmd_ps_mode mode;
3879
3880 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003881 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003882 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003883 true);
3884 if (ret < 0)
3885 goto out;
3886 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003887 }
3888
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003889 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003890 if (sta_exists) {
3891 if ((changed & BSS_CHANGED_HT) &&
3892 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003893 ret = wl1271_acx_set_ht_capabilities(wl,
3894 &sta_ht_cap,
3895 true,
Eliad Peller154da672011-10-05 11:55:53 +02003896 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003897 if (ret < 0) {
3898 wl1271_warning("Set ht cap true failed %d",
3899 ret);
3900 goto out;
3901 }
3902 }
3903 /* handle new association without HT and disassociation */
3904 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003905 ret = wl1271_acx_set_ht_capabilities(wl,
3906 &sta_ht_cap,
3907 false,
Eliad Peller154da672011-10-05 11:55:53 +02003908 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003909 if (ret < 0) {
3910 wl1271_warning("Set ht cap false failed %d",
3911 ret);
3912 goto out;
3913 }
3914 }
3915 }
3916
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003917 /* Handle HT information change. Done after join. */
3918 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003919 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003920 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003921 bss_conf->ht_operation_mode);
3922 if (ret < 0) {
3923 wl1271_warning("Set ht information failed %d", ret);
3924 goto out;
3925 }
3926 }
3927
Arik Nemtsove78a2872010-10-16 19:07:21 +02003928out:
3929 return;
3930}
3931
3932static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3933 struct ieee80211_vif *vif,
3934 struct ieee80211_bss_conf *bss_conf,
3935 u32 changed)
3936{
3937 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02003938 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3939 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003940 int ret;
3941
3942 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3943 (int)changed);
3944
3945 mutex_lock(&wl->mutex);
3946
3947 if (unlikely(wl->state == WL1271_STATE_OFF))
3948 goto out;
3949
Eliad Peller10c8cd02011-10-10 10:13:06 +02003950 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3951 goto out;
3952
Ido Yariva6208652011-03-01 15:14:41 +02003953 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003954 if (ret < 0)
3955 goto out;
3956
3957 if (is_ap)
3958 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3959 else
3960 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3961
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003962 wl1271_ps_elp_sleep(wl);
3963
3964out:
3965 mutex_unlock(&wl->mutex);
3966}
3967
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003968static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3969 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003970 const struct ieee80211_tx_queue_params *params)
3971{
3972 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003973 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003974 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003975 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003976
3977 mutex_lock(&wl->mutex);
3978
3979 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3980
Kalle Valo4695dc92010-03-18 12:26:38 +02003981 if (params->uapsd)
3982 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3983 else
3984 ps_scheme = CONF_PS_SCHEME_LEGACY;
3985
Eliad Peller5b37ddf2011-12-18 20:25:40 +02003986 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003987 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003988
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003989 ret = wl1271_ps_elp_wakeup(wl);
3990 if (ret < 0)
3991 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003992
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003993 /*
3994 * the txop is confed in units of 32us by the mac80211,
3995 * we need us
3996 */
Eliad Peller0603d892011-10-05 11:55:51 +02003997 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003998 params->cw_min, params->cw_max,
3999 params->aifs, params->txop << 5);
4000 if (ret < 0)
4001 goto out_sleep;
4002
Eliad Peller0603d892011-10-05 11:55:51 +02004003 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004004 CONF_CHANNEL_TYPE_EDCF,
4005 wl1271_tx_get_queue(queue),
4006 ps_scheme, CONF_ACK_POLICY_LEGACY,
4007 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004008
4009out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004010 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004011
4012out:
4013 mutex_unlock(&wl->mutex);
4014
4015 return ret;
4016}
4017
Eliad Peller37a41b42011-09-21 14:06:11 +03004018static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4019 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004020{
4021
4022 struct wl1271 *wl = hw->priv;
4023 u64 mactime = ULLONG_MAX;
4024 int ret;
4025
4026 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4027
4028 mutex_lock(&wl->mutex);
4029
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004030 if (unlikely(wl->state == WL1271_STATE_OFF))
4031 goto out;
4032
Ido Yariva6208652011-03-01 15:14:41 +02004033 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004034 if (ret < 0)
4035 goto out;
4036
4037 ret = wl1271_acx_tsf_info(wl, &mactime);
4038 if (ret < 0)
4039 goto out_sleep;
4040
4041out_sleep:
4042 wl1271_ps_elp_sleep(wl);
4043
4044out:
4045 mutex_unlock(&wl->mutex);
4046 return mactime;
4047}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004048
John W. Linvilleece550d2010-07-28 16:41:06 -04004049static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4050 struct survey_info *survey)
4051{
4052 struct wl1271 *wl = hw->priv;
4053 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004054
John W. Linvilleece550d2010-07-28 16:41:06 -04004055 if (idx != 0)
4056 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004057
John W. Linvilleece550d2010-07-28 16:41:06 -04004058 survey->channel = conf->channel;
4059 survey->filled = SURVEY_INFO_NOISE_DBM;
4060 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004061
John W. Linvilleece550d2010-07-28 16:41:06 -04004062 return 0;
4063}
4064
Arik Nemtsov409622e2011-02-23 00:22:29 +02004065static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004066 struct wl12xx_vif *wlvif,
4067 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004068{
4069 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004070 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004071
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004072
4073 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004074 wl1271_warning("could not allocate HLID - too much stations");
4075 return -EBUSY;
4076 }
4077
4078 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004079 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4080 if (ret < 0) {
4081 wl1271_warning("could not allocate HLID - too many links");
4082 return -EBUSY;
4083 }
4084
4085 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004086 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004087 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004088 return 0;
4089}
4090
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004091void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004092{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004093 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004094 return;
4095
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004096 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004097 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004098 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004099 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004100 __clear_bit(hlid, &wl->ap_ps_map);
4101 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004102 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004103 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004104}
4105
4106static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4107 struct ieee80211_vif *vif,
4108 struct ieee80211_sta *sta)
4109{
4110 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004111 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004112 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004113 int ret = 0;
4114 u8 hlid;
4115
4116 mutex_lock(&wl->mutex);
4117
4118 if (unlikely(wl->state == WL1271_STATE_OFF))
4119 goto out;
4120
Eliad Peller536129c82011-10-05 11:55:45 +02004121 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004122 goto out;
4123
4124 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4125
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004126 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004127 if (ret < 0)
4128 goto out;
4129
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004130 wl_sta = (struct wl1271_station *)sta->drv_priv;
4131 hlid = wl_sta->hlid;
4132
Ido Yariva6208652011-03-01 15:14:41 +02004133 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004134 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004135 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004136
Eliad Peller1b92f152011-10-10 10:13:09 +02004137 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004138 if (ret < 0)
4139 goto out_sleep;
4140
Eliad Pellerb67476e2011-08-14 13:17:23 +03004141 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4142 if (ret < 0)
4143 goto out_sleep;
4144
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004145 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4146 if (ret < 0)
4147 goto out_sleep;
4148
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004149out_sleep:
4150 wl1271_ps_elp_sleep(wl);
4151
Arik Nemtsov409622e2011-02-23 00:22:29 +02004152out_free_sta:
4153 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004154 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004155
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004156out:
4157 mutex_unlock(&wl->mutex);
4158 return ret;
4159}
4160
4161static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4162 struct ieee80211_vif *vif,
4163 struct ieee80211_sta *sta)
4164{
4165 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004166 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004167 struct wl1271_station *wl_sta;
4168 int ret = 0, id;
4169
4170 mutex_lock(&wl->mutex);
4171
4172 if (unlikely(wl->state == WL1271_STATE_OFF))
4173 goto out;
4174
Eliad Peller536129c82011-10-05 11:55:45 +02004175 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004176 goto out;
4177
4178 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4179
4180 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004181 id = wl_sta->hlid;
4182 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004183 goto out;
4184
Ido Yariva6208652011-03-01 15:14:41 +02004185 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004186 if (ret < 0)
4187 goto out;
4188
Eliad Pellerc690ec82011-08-14 13:17:07 +03004189 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004190 if (ret < 0)
4191 goto out_sleep;
4192
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004193 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004194
4195out_sleep:
4196 wl1271_ps_elp_sleep(wl);
4197
4198out:
4199 mutex_unlock(&wl->mutex);
4200 return ret;
4201}
4202
Luciano Coelho4623ec72011-03-21 19:26:41 +02004203static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4204 struct ieee80211_vif *vif,
4205 enum ieee80211_ampdu_mlme_action action,
4206 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4207 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004208{
4209 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004210 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004211 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004212 u8 hlid, *ba_bitmap;
4213
4214 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4215 tid);
4216
4217 /* sanity check - the fields in FW are only 8bits wide */
4218 if (WARN_ON(tid > 0xFF))
4219 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004220
4221 mutex_lock(&wl->mutex);
4222
4223 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4224 ret = -EAGAIN;
4225 goto out;
4226 }
4227
Eliad Peller536129c82011-10-05 11:55:45 +02004228 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004229 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004230 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c82011-10-05 11:55:45 +02004231 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004232 struct wl1271_station *wl_sta;
4233
4234 wl_sta = (struct wl1271_station *)sta->drv_priv;
4235 hlid = wl_sta->hlid;
4236 ba_bitmap = &wl->links[hlid].ba_bitmap;
4237 } else {
4238 ret = -EINVAL;
4239 goto out;
4240 }
4241
Ido Yariva6208652011-03-01 15:14:41 +02004242 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004243 if (ret < 0)
4244 goto out;
4245
Shahar Levi70559a02011-05-22 16:10:22 +03004246 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4247 tid, action);
4248
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004249 switch (action) {
4250 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004251 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004252 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004253 break;
4254 }
4255
4256 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4257 ret = -EBUSY;
4258 wl1271_error("exceeded max RX BA sessions");
4259 break;
4260 }
4261
4262 if (*ba_bitmap & BIT(tid)) {
4263 ret = -EINVAL;
4264 wl1271_error("cannot enable RX BA session on active "
4265 "tid: %d", tid);
4266 break;
4267 }
4268
4269 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4270 hlid);
4271 if (!ret) {
4272 *ba_bitmap |= BIT(tid);
4273 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004274 }
4275 break;
4276
4277 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004278 if (!(*ba_bitmap & BIT(tid))) {
4279 ret = -EINVAL;
4280 wl1271_error("no active RX BA session on tid: %d",
4281 tid);
4282 break;
4283 }
4284
4285 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4286 hlid);
4287 if (!ret) {
4288 *ba_bitmap &= ~BIT(tid);
4289 wl->ba_rx_session_count--;
4290 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004291 break;
4292
4293 /*
4294 * The BA initiator session management in FW independently.
4295 * Falling break here on purpose for all TX APDU commands.
4296 */
4297 case IEEE80211_AMPDU_TX_START:
4298 case IEEE80211_AMPDU_TX_STOP:
4299 case IEEE80211_AMPDU_TX_OPERATIONAL:
4300 ret = -EINVAL;
4301 break;
4302
4303 default:
4304 wl1271_error("Incorrect ampdu action id=%x\n", action);
4305 ret = -EINVAL;
4306 }
4307
4308 wl1271_ps_elp_sleep(wl);
4309
4310out:
4311 mutex_unlock(&wl->mutex);
4312
4313 return ret;
4314}
4315
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004316static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4317 struct ieee80211_vif *vif,
4318 const struct cfg80211_bitrate_mask *mask)
4319{
Eliad Peller83587502011-10-10 10:12:53 +02004320 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004321 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004322 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004323
4324 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4325 mask->control[NL80211_BAND_2GHZ].legacy,
4326 mask->control[NL80211_BAND_5GHZ].legacy);
4327
4328 mutex_lock(&wl->mutex);
4329
4330 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004331 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004332 wl1271_tx_enabled_rates_get(wl,
4333 mask->control[i].legacy,
4334 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004335
4336 if (unlikely(wl->state == WL1271_STATE_OFF))
4337 goto out;
4338
4339 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4340 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4341
4342 ret = wl1271_ps_elp_wakeup(wl);
4343 if (ret < 0)
4344 goto out;
4345
4346 wl1271_set_band_rate(wl, wlvif);
4347 wlvif->basic_rate =
4348 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4349 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4350
4351 wl1271_ps_elp_sleep(wl);
4352 }
4353out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004354 mutex_unlock(&wl->mutex);
4355
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004356 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004357}
4358
Shahar Levi6d158ff2011-09-08 13:01:33 +03004359static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4360 struct ieee80211_channel_switch *ch_switch)
4361{
4362 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004363 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004364 int ret;
4365
4366 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4367
4368 mutex_lock(&wl->mutex);
4369
4370 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004371 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4372 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4373 ieee80211_chswitch_done(vif, false);
4374 }
4375 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004376 }
4377
4378 ret = wl1271_ps_elp_wakeup(wl);
4379 if (ret < 0)
4380 goto out;
4381
Eliad Peller52630c52011-10-10 10:13:08 +02004382 /* TODO: change mac80211 to pass vif as param */
4383 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4384 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004385
Eliad Peller52630c52011-10-10 10:13:08 +02004386 if (!ret)
4387 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4388 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004389
4390 wl1271_ps_elp_sleep(wl);
4391
4392out:
4393 mutex_unlock(&wl->mutex);
4394}
4395
Arik Nemtsov33437892011-04-26 23:35:39 +03004396static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4397{
4398 struct wl1271 *wl = hw->priv;
4399 bool ret = false;
4400
4401 mutex_lock(&wl->mutex);
4402
4403 if (unlikely(wl->state == WL1271_STATE_OFF))
4404 goto out;
4405
4406 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004407 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004408out:
4409 mutex_unlock(&wl->mutex);
4410
4411 return ret;
4412}
4413
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004414/* can't be const, mac80211 writes to this */
4415static struct ieee80211_rate wl1271_rates[] = {
4416 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004417 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4418 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004419 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004420 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4421 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004422 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4423 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004424 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4425 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004426 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4427 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004428 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4429 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004430 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4431 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004432 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4433 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004434 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004435 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4436 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004437 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004438 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4439 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004440 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004441 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4442 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004443 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004444 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4445 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004446 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004447 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4448 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004449 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004450 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4451 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004452 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004453 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4454 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004455};
4456
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004457/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004458static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004459 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004460 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004461 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4462 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4463 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004464 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004465 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4466 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4467 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004468 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004469 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4470 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4471 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004472 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004473};
4474
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004475/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004476static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004477 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004478 7, /* CONF_HW_RXTX_RATE_MCS7 */
4479 6, /* CONF_HW_RXTX_RATE_MCS6 */
4480 5, /* CONF_HW_RXTX_RATE_MCS5 */
4481 4, /* CONF_HW_RXTX_RATE_MCS4 */
4482 3, /* CONF_HW_RXTX_RATE_MCS3 */
4483 2, /* CONF_HW_RXTX_RATE_MCS2 */
4484 1, /* CONF_HW_RXTX_RATE_MCS1 */
4485 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004486
4487 11, /* CONF_HW_RXTX_RATE_54 */
4488 10, /* CONF_HW_RXTX_RATE_48 */
4489 9, /* CONF_HW_RXTX_RATE_36 */
4490 8, /* CONF_HW_RXTX_RATE_24 */
4491
4492 /* TI-specific rate */
4493 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4494
4495 7, /* CONF_HW_RXTX_RATE_18 */
4496 6, /* CONF_HW_RXTX_RATE_12 */
4497 3, /* CONF_HW_RXTX_RATE_11 */
4498 5, /* CONF_HW_RXTX_RATE_9 */
4499 4, /* CONF_HW_RXTX_RATE_6 */
4500 2, /* CONF_HW_RXTX_RATE_5_5 */
4501 1, /* CONF_HW_RXTX_RATE_2 */
4502 0 /* CONF_HW_RXTX_RATE_1 */
4503};
4504
Shahar Levie8b03a22010-10-13 16:09:39 +02004505/* 11n STA capabilities */
4506#define HW_RX_HIGHEST_RATE 72
4507
Shahar Levi00d20102010-11-08 11:20:10 +00004508#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004509 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4510 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004511 .ht_supported = true, \
4512 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4513 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4514 .mcs = { \
4515 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4516 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4517 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4518 }, \
4519}
4520
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004521/* can't be const, mac80211 writes to this */
4522static struct ieee80211_supported_band wl1271_band_2ghz = {
4523 .channels = wl1271_channels,
4524 .n_channels = ARRAY_SIZE(wl1271_channels),
4525 .bitrates = wl1271_rates,
4526 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004527 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004528};
4529
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004530/* 5 GHz data rates for WL1273 */
4531static struct ieee80211_rate wl1271_rates_5ghz[] = {
4532 { .bitrate = 60,
4533 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4534 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4535 { .bitrate = 90,
4536 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4537 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4538 { .bitrate = 120,
4539 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4540 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4541 { .bitrate = 180,
4542 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4543 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4544 { .bitrate = 240,
4545 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4546 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4547 { .bitrate = 360,
4548 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4549 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4550 { .bitrate = 480,
4551 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4552 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4553 { .bitrate = 540,
4554 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4555 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4556};
4557
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004558/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004559static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004560 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4561 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4562 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4563 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4564 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4565 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4566 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4567 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4568 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4569 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4570 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4571 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4572 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4573 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4574 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4575 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4576 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4577 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4578 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4579 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4580 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4581 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4582 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4583 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4584 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4585 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4586 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4587 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4588 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4589 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4590 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4591 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4592 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4593 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004594};
4595
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004596/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004597static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004598 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004599 7, /* CONF_HW_RXTX_RATE_MCS7 */
4600 6, /* CONF_HW_RXTX_RATE_MCS6 */
4601 5, /* CONF_HW_RXTX_RATE_MCS5 */
4602 4, /* CONF_HW_RXTX_RATE_MCS4 */
4603 3, /* CONF_HW_RXTX_RATE_MCS3 */
4604 2, /* CONF_HW_RXTX_RATE_MCS2 */
4605 1, /* CONF_HW_RXTX_RATE_MCS1 */
4606 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004607
4608 7, /* CONF_HW_RXTX_RATE_54 */
4609 6, /* CONF_HW_RXTX_RATE_48 */
4610 5, /* CONF_HW_RXTX_RATE_36 */
4611 4, /* CONF_HW_RXTX_RATE_24 */
4612
4613 /* TI-specific rate */
4614 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4615
4616 3, /* CONF_HW_RXTX_RATE_18 */
4617 2, /* CONF_HW_RXTX_RATE_12 */
4618 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4619 1, /* CONF_HW_RXTX_RATE_9 */
4620 0, /* CONF_HW_RXTX_RATE_6 */
4621 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4622 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4623 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4624};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004625
4626static struct ieee80211_supported_band wl1271_band_5ghz = {
4627 .channels = wl1271_channels_5ghz,
4628 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4629 .bitrates = wl1271_rates_5ghz,
4630 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004631 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004632};
4633
Tobias Klausera0ea9492010-05-20 10:38:11 +02004634static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004635 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4636 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4637};
4638
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004639static const struct ieee80211_ops wl1271_ops = {
4640 .start = wl1271_op_start,
4641 .stop = wl1271_op_stop,
4642 .add_interface = wl1271_op_add_interface,
4643 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004644 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004645#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004646 .suspend = wl1271_op_suspend,
4647 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004648#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004649 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004650 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004651 .configure_filter = wl1271_op_configure_filter,
4652 .tx = wl1271_op_tx,
4653 .set_key = wl1271_op_set_key,
4654 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004655 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004656 .sched_scan_start = wl1271_op_sched_scan_start,
4657 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004658 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004659 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004660 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004661 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004662 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004663 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004664 .sta_add = wl1271_op_sta_add,
4665 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004666 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004667 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004668 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004669 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004670 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004671};
4672
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004673
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004674u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004675{
4676 u8 idx;
4677
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004678 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004679
4680 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4681 wl1271_error("Illegal RX rate from HW: %d", rate);
4682 return 0;
4683 }
4684
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004685 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004686 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4687 wl1271_error("Unsupported RX rate from HW: %d", rate);
4688 return 0;
4689 }
4690
4691 return idx;
4692}
4693
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004694static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4695 struct device_attribute *attr,
4696 char *buf)
4697{
4698 struct wl1271 *wl = dev_get_drvdata(dev);
4699 ssize_t len;
4700
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004701 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004702
4703 mutex_lock(&wl->mutex);
4704 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4705 wl->sg_enabled);
4706 mutex_unlock(&wl->mutex);
4707
4708 return len;
4709
4710}
4711
4712static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4713 struct device_attribute *attr,
4714 const char *buf, size_t count)
4715{
4716 struct wl1271 *wl = dev_get_drvdata(dev);
4717 unsigned long res;
4718 int ret;
4719
Luciano Coelho6277ed62011-04-01 17:49:54 +03004720 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004721 if (ret < 0) {
4722 wl1271_warning("incorrect value written to bt_coex_mode");
4723 return count;
4724 }
4725
4726 mutex_lock(&wl->mutex);
4727
4728 res = !!res;
4729
4730 if (res == wl->sg_enabled)
4731 goto out;
4732
4733 wl->sg_enabled = res;
4734
4735 if (wl->state == WL1271_STATE_OFF)
4736 goto out;
4737
Ido Yariva6208652011-03-01 15:14:41 +02004738 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004739 if (ret < 0)
4740 goto out;
4741
4742 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4743 wl1271_ps_elp_sleep(wl);
4744
4745 out:
4746 mutex_unlock(&wl->mutex);
4747 return count;
4748}
4749
4750static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4751 wl1271_sysfs_show_bt_coex_state,
4752 wl1271_sysfs_store_bt_coex_state);
4753
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004754static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4755 struct device_attribute *attr,
4756 char *buf)
4757{
4758 struct wl1271 *wl = dev_get_drvdata(dev);
4759 ssize_t len;
4760
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004761 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004762
4763 mutex_lock(&wl->mutex);
4764 if (wl->hw_pg_ver >= 0)
4765 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4766 else
4767 len = snprintf(buf, len, "n/a\n");
4768 mutex_unlock(&wl->mutex);
4769
4770 return len;
4771}
4772
Gery Kahn6f07b722011-07-18 14:21:49 +03004773static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004774 wl1271_sysfs_show_hw_pg_ver, NULL);
4775
Ido Yariv95dac04f2011-06-06 14:57:06 +03004776static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4777 struct bin_attribute *bin_attr,
4778 char *buffer, loff_t pos, size_t count)
4779{
4780 struct device *dev = container_of(kobj, struct device, kobj);
4781 struct wl1271 *wl = dev_get_drvdata(dev);
4782 ssize_t len;
4783 int ret;
4784
4785 ret = mutex_lock_interruptible(&wl->mutex);
4786 if (ret < 0)
4787 return -ERESTARTSYS;
4788
4789 /* Let only one thread read the log at a time, blocking others */
4790 while (wl->fwlog_size == 0) {
4791 DEFINE_WAIT(wait);
4792
4793 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4794 &wait,
4795 TASK_INTERRUPTIBLE);
4796
4797 if (wl->fwlog_size != 0) {
4798 finish_wait(&wl->fwlog_waitq, &wait);
4799 break;
4800 }
4801
4802 mutex_unlock(&wl->mutex);
4803
4804 schedule();
4805 finish_wait(&wl->fwlog_waitq, &wait);
4806
4807 if (signal_pending(current))
4808 return -ERESTARTSYS;
4809
4810 ret = mutex_lock_interruptible(&wl->mutex);
4811 if (ret < 0)
4812 return -ERESTARTSYS;
4813 }
4814
4815 /* Check if the fwlog is still valid */
4816 if (wl->fwlog_size < 0) {
4817 mutex_unlock(&wl->mutex);
4818 return 0;
4819 }
4820
4821 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4822 len = min(count, (size_t)wl->fwlog_size);
4823 wl->fwlog_size -= len;
4824 memcpy(buffer, wl->fwlog, len);
4825
4826 /* Make room for new messages */
4827 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4828
4829 mutex_unlock(&wl->mutex);
4830
4831 return len;
4832}
4833
4834static struct bin_attribute fwlog_attr = {
4835 .attr = {.name = "fwlog", .mode = S_IRUSR},
4836 .read = wl1271_sysfs_read_fwlog,
4837};
4838
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004839static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004840{
4841 int ret;
4842
4843 if (wl->mac80211_registered)
4844 return 0;
4845
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004846 ret = wl1271_fetch_nvs(wl);
4847 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004848 /* NOTE: The wl->nvs->nvs element must be first, in
4849 * order to simplify the casting, we assume it is at
4850 * the beginning of the wl->nvs structure.
4851 */
4852 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004853
4854 wl->mac_addr[0] = nvs_ptr[11];
4855 wl->mac_addr[1] = nvs_ptr[10];
4856 wl->mac_addr[2] = nvs_ptr[6];
4857 wl->mac_addr[3] = nvs_ptr[5];
4858 wl->mac_addr[4] = nvs_ptr[4];
4859 wl->mac_addr[5] = nvs_ptr[3];
4860 }
4861
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004862 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4863
4864 ret = ieee80211_register_hw(wl->hw);
4865 if (ret < 0) {
4866 wl1271_error("unable to register mac80211 hw: %d", ret);
4867 return ret;
4868 }
4869
4870 wl->mac80211_registered = true;
4871
Eliad Pellerd60080a2010-11-24 12:53:16 +02004872 wl1271_debugfs_init(wl);
4873
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004874 register_netdevice_notifier(&wl1271_dev_notifier);
4875
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004876 wl1271_notice("loaded");
4877
4878 return 0;
4879}
4880
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004881static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004882{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004883 if (wl->state == WL1271_STATE_PLT)
4884 __wl1271_plt_stop(wl);
4885
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004886 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004887 ieee80211_unregister_hw(wl->hw);
4888 wl->mac80211_registered = false;
4889
4890}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004891
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004892static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004893{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004894 static const u32 cipher_suites[] = {
4895 WLAN_CIPHER_SUITE_WEP40,
4896 WLAN_CIPHER_SUITE_WEP104,
4897 WLAN_CIPHER_SUITE_TKIP,
4898 WLAN_CIPHER_SUITE_CCMP,
4899 WL1271_CIPHER_SUITE_GEM,
4900 };
4901
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004902 /* The tx descriptor buffer and the TKIP space. */
4903 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4904 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004905
4906 /* unit us */
4907 /* FIXME: find a proper value */
4908 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004909 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004910
4911 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004912 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004913 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004914 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004915 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004916 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004917 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004918 IEEE80211_HW_AP_LINK_PS |
4919 IEEE80211_HW_AMPDU_AGGREGATION |
4920 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004921
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004922 wl->hw->wiphy->cipher_suites = cipher_suites;
4923 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4924
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004925 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004926 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4927 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004928 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004929 wl->hw->wiphy->max_sched_scan_ssids = 16;
4930 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004931 /*
4932 * Maximum length of elements in scanning probe request templates
4933 * should be the maximum length possible for a template, without
4934 * the IEEE80211 header of the template
4935 */
Eliad Peller154037d2011-08-14 13:17:12 +03004936 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004937 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004938
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004939 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4940 sizeof(struct ieee80211_header);
4941
Eliad Peller1ec23f72011-08-25 14:26:54 +03004942 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4943
Luciano Coelho4a31c112011-03-21 23:16:14 +02004944 /* make sure all our channels fit in the scanned_ch bitmask */
4945 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4946 ARRAY_SIZE(wl1271_channels_5ghz) >
4947 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004948 /*
4949 * We keep local copies of the band structs because we need to
4950 * modify them on a per-device basis.
4951 */
4952 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4953 sizeof(wl1271_band_2ghz));
4954 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4955 sizeof(wl1271_band_5ghz));
4956
4957 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4958 &wl->bands[IEEE80211_BAND_2GHZ];
4959 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4960 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004961
Kalle Valo12bd8942010-03-18 12:26:33 +02004962 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004963 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004964
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004965 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4966
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02004967 /* the FW answers probe-requests in AP-mode */
4968 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
4969 wl->hw->wiphy->probe_resp_offload =
4970 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
4971 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
4972 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
4973
Felipe Balbia390e852011-10-06 10:07:44 +03004974 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004975
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004976 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004977 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004978
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004979 wl->hw->max_rx_aggregation_subframes = 8;
4980
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004981 return 0;
4982}
4983
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004984#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004985
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004986static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004987{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004988 struct ieee80211_hw *hw;
4989 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004990 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004991 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004992
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004993 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004994
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004995 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4996 if (!hw) {
4997 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004998 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004999 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005000 }
5001
5002 wl = hw->priv;
5003 memset(wl, 0, sizeof(*wl));
5004
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005005 INIT_LIST_HEAD(&wl->list);
Eliad Peller876272142011-10-10 10:12:54 +02005006 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005007
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005008 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005009
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005010 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005011 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005012 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5013
Ido Yariva6208652011-03-01 15:14:41 +02005014 skb_queue_head_init(&wl->deferred_rx_queue);
5015 skb_queue_head_init(&wl->deferred_tx_queue);
5016
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005017 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005018 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005019 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5020 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5021 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005022
Eliad Peller92ef8962011-06-07 12:50:46 +03005023 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5024 if (!wl->freezable_wq) {
5025 ret = -ENOMEM;
5026 goto err_hw;
5027 }
5028
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005029 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005030 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005031 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005032 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005033 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005034 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005035 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005036 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005037 wl->ap_ps_map = 0;
5038 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005039 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005040 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005041 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005042 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005043 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005044 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005045 wl->fwlog_size = 0;
5046 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005047
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005048 /* The system link is always allocated */
5049 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5050
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005051 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005052 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005053 wl->tx_frames[i] = NULL;
5054
5055 spin_lock_init(&wl->wl_lock);
5056
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005057 wl->state = WL1271_STATE_OFF;
5058 mutex_init(&wl->mutex);
5059
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005060 /* Apply default driver configuration. */
5061 wl1271_conf_init(wl);
5062
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005063 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5064 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5065 if (!wl->aggr_buf) {
5066 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005067 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005068 }
5069
Ido Yariv990f5de2011-03-31 10:06:59 +02005070 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5071 if (!wl->dummy_packet) {
5072 ret = -ENOMEM;
5073 goto err_aggr;
5074 }
5075
Ido Yariv95dac04f2011-06-06 14:57:06 +03005076 /* Allocate one page for the FW log */
5077 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5078 if (!wl->fwlog) {
5079 ret = -ENOMEM;
5080 goto err_dummy_packet;
5081 }
5082
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005083 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005084
Ido Yariv990f5de2011-03-31 10:06:59 +02005085err_dummy_packet:
5086 dev_kfree_skb(wl->dummy_packet);
5087
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005088err_aggr:
5089 free_pages((unsigned long)wl->aggr_buf, order);
5090
Eliad Peller92ef8962011-06-07 12:50:46 +03005091err_wq:
5092 destroy_workqueue(wl->freezable_wq);
5093
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005094err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005095 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005096 ieee80211_free_hw(hw);
5097
5098err_hw_alloc:
5099
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005100 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005101}
5102
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005103static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005104{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005105 /* Unblock any fwlog readers */
5106 mutex_lock(&wl->mutex);
5107 wl->fwlog_size = -1;
5108 wake_up_interruptible_all(&wl->fwlog_waitq);
5109 mutex_unlock(&wl->mutex);
5110
Felipe Balbif79f8902011-10-06 13:05:25 +03005111 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005112
Felipe Balbif79f8902011-10-06 13:05:25 +03005113 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005114
Felipe Balbif79f8902011-10-06 13:05:25 +03005115 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005116 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005117 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005118 free_pages((unsigned long)wl->aggr_buf,
5119 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005120
5121 wl1271_debugfs_exit(wl);
5122
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005123 vfree(wl->fw);
5124 wl->fw = NULL;
5125 kfree(wl->nvs);
5126 wl->nvs = NULL;
5127
5128 kfree(wl->fw_status);
5129 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005130 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005131
5132 ieee80211_free_hw(wl->hw);
5133
5134 return 0;
5135}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005136
Felipe Balbia390e852011-10-06 10:07:44 +03005137static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5138{
5139 struct wl1271 *wl = cookie;
5140 unsigned long flags;
5141
5142 wl1271_debug(DEBUG_IRQ, "IRQ");
5143
5144 /* complete the ELP completion */
5145 spin_lock_irqsave(&wl->wl_lock, flags);
5146 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5147 if (wl->elp_compl) {
5148 complete(wl->elp_compl);
5149 wl->elp_compl = NULL;
5150 }
5151
5152 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5153 /* don't enqueue a work right now. mark it as pending */
5154 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5155 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5156 disable_irq_nosync(wl->irq);
5157 pm_wakeup_event(wl->dev, 0);
5158 spin_unlock_irqrestore(&wl->wl_lock, flags);
5159 return IRQ_HANDLED;
5160 }
5161 spin_unlock_irqrestore(&wl->wl_lock, flags);
5162
5163 return IRQ_WAKE_THREAD;
5164}
5165
Felipe Balbice2a2172011-10-05 14:12:55 +03005166static int __devinit wl12xx_probe(struct platform_device *pdev)
5167{
Felipe Balbia390e852011-10-06 10:07:44 +03005168 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5169 struct ieee80211_hw *hw;
5170 struct wl1271 *wl;
5171 unsigned long irqflags;
5172 int ret = -ENODEV;
5173
5174 hw = wl1271_alloc_hw();
5175 if (IS_ERR(hw)) {
5176 wl1271_error("can't allocate hw");
5177 ret = PTR_ERR(hw);
5178 goto out;
5179 }
5180
5181 wl = hw->priv;
5182 wl->irq = platform_get_irq(pdev, 0);
5183 wl->ref_clock = pdata->board_ref_clock;
5184 wl->tcxo_clock = pdata->board_tcxo_clock;
5185 wl->platform_quirks = pdata->platform_quirks;
5186 wl->set_power = pdata->set_power;
5187 wl->dev = &pdev->dev;
5188 wl->if_ops = pdata->ops;
5189
5190 platform_set_drvdata(pdev, wl);
5191
5192 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5193 irqflags = IRQF_TRIGGER_RISING;
5194 else
5195 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5196
5197 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5198 irqflags,
5199 pdev->name, wl);
5200 if (ret < 0) {
5201 wl1271_error("request_irq() failed: %d", ret);
5202 goto out_free_hw;
5203 }
5204
5205 ret = enable_irq_wake(wl->irq);
5206 if (!ret) {
5207 wl->irq_wake_enabled = true;
5208 device_init_wakeup(wl->dev, 1);
5209 if (pdata->pwr_in_suspend)
5210 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5211
5212 }
5213 disable_irq(wl->irq);
5214
5215 ret = wl1271_init_ieee80211(wl);
5216 if (ret)
5217 goto out_irq;
5218
5219 ret = wl1271_register_hw(wl);
5220 if (ret)
5221 goto out_irq;
5222
Felipe Balbif79f8902011-10-06 13:05:25 +03005223 /* Create sysfs file to control bt coex state */
5224 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5225 if (ret < 0) {
5226 wl1271_error("failed to create sysfs file bt_coex_state");
5227 goto out_irq;
5228 }
5229
5230 /* Create sysfs file to get HW PG version */
5231 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5232 if (ret < 0) {
5233 wl1271_error("failed to create sysfs file hw_pg_ver");
5234 goto out_bt_coex_state;
5235 }
5236
5237 /* Create sysfs file for the FW log */
5238 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5239 if (ret < 0) {
5240 wl1271_error("failed to create sysfs file fwlog");
5241 goto out_hw_pg_ver;
5242 }
5243
Felipe Balbice2a2172011-10-05 14:12:55 +03005244 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005245
Felipe Balbif79f8902011-10-06 13:05:25 +03005246out_hw_pg_ver:
5247 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5248
5249out_bt_coex_state:
5250 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5251
Felipe Balbia390e852011-10-06 10:07:44 +03005252out_irq:
5253 free_irq(wl->irq, wl);
5254
5255out_free_hw:
5256 wl1271_free_hw(wl);
5257
5258out:
5259 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005260}
5261
5262static int __devexit wl12xx_remove(struct platform_device *pdev)
5263{
Felipe Balbia390e852011-10-06 10:07:44 +03005264 struct wl1271 *wl = platform_get_drvdata(pdev);
5265
5266 if (wl->irq_wake_enabled) {
5267 device_init_wakeup(wl->dev, 0);
5268 disable_irq_wake(wl->irq);
5269 }
5270 wl1271_unregister_hw(wl);
5271 free_irq(wl->irq, wl);
5272 wl1271_free_hw(wl);
5273
Felipe Balbice2a2172011-10-05 14:12:55 +03005274 return 0;
5275}
5276
5277static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005278 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005279 { } /* Terminating Entry */
5280};
5281MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5282
5283static struct platform_driver wl12xx_driver = {
5284 .probe = wl12xx_probe,
5285 .remove = __devexit_p(wl12xx_remove),
5286 .id_table = wl12xx_id_table,
5287 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005288 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005289 .owner = THIS_MODULE,
5290 }
5291};
5292
5293static int __init wl12xx_init(void)
5294{
5295 return platform_driver_register(&wl12xx_driver);
5296}
5297module_init(wl12xx_init);
5298
5299static void __exit wl12xx_exit(void)
5300{
5301 platform_driver_unregister(&wl12xx_driver);
5302}
5303module_exit(wl12xx_exit);
5304
Guy Eilam491bbd62011-01-12 10:33:29 +01005305u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005306EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005307module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005308MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5309
Ido Yariv95dac04f2011-06-06 14:57:06 +03005310module_param_named(fwlog, fwlog_param, charp, 0);
5311MODULE_PARM_DESC(keymap,
5312 "FW logger options: continuous, ondemand, dbgpins or disable");
5313
Eliad Peller2a5bff02011-08-25 18:10:59 +03005314module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5315MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5316
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005317MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005318MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005319MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");