blob: d5f55a149de5e43216ad46c7ebf0d4825e9d0628 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Felipe Balbia390e852011-10-06 10:07:44 +030035#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "wl12xx.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030038#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030039#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000040#include "reg.h"
41#include "io.h"
42#include "event.h"
43#include "tx.h"
44#include "rx.h"
45#include "ps.h"
46#include "init.h"
47#include "debugfs.h"
48#include "cmd.h"
49#include "boot.h"
50#include "testmode.h"
51#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030052
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020053#define WL1271_BOOT_RETRIES 3
54
Juuso Oikarinen8a080482009-10-13 12:47:44 +030055static struct conf_drv_settings default_conf = {
56 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030057 .params = {
58 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
61 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
62 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
64 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
65 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
66 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
68 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
69 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
70 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
71 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
73 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
74 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
75 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
76 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
77 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
78 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
79 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
82 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
83 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
84 /* active scan params */
85 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
86 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
87 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
88 /* passive scan params */
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
91 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
92 /* passive scan in dual antenna params */
93 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
94 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
95 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
96 /* general params */
97 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
98 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
99 [CONF_SG_BEACON_MISS_PERCENT] = 60,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_RXT] = 1200,
102 [CONF_SG_TXT] = 1000,
103 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
104 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
105 [CONF_SG_HV3_MAX_SERVED] = 6,
106 [CONF_SG_PS_POLL_TIMEOUT] = 10,
107 [CONF_SG_UPSD_TIMEOUT] = 10,
108 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
109 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
110 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
111 /* AP params */
112 [CONF_AP_BEACON_MISS_TX] = 3,
113 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
114 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
115 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
116 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
117 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300118 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200119 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300120 },
121 .rx = {
122 .rx_msdu_life_time = 512000,
123 .packet_detection_threshold = 0,
124 .ps_poll_timeout = 15,
125 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300126 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200127 .rx_cca_threshold = 0,
128 .irq_blk_threshold = 0xFFFF,
129 .irq_pkt_threshold = 0,
130 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300131 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
132 },
133 .tx = {
134 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200135 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300136 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300137 .short_retry_limit = 10,
138 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200139 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300140 },
141 .ac_conf_count = 4,
142 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200143 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300144 .ac = CONF_TX_AC_BE,
145 .cw_min = 15,
146 .cw_max = 63,
147 .aifsn = 3,
148 .tx_op_limit = 0,
149 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200150 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300151 .ac = CONF_TX_AC_BK,
152 .cw_min = 15,
153 .cw_max = 63,
154 .aifsn = 7,
155 .tx_op_limit = 0,
156 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200157 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300158 .ac = CONF_TX_AC_VI,
159 .cw_min = 15,
160 .cw_max = 63,
161 .aifsn = CONF_TX_AIFS_PIFS,
162 .tx_op_limit = 3008,
163 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200164 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300165 .ac = CONF_TX_AC_VO,
166 .cw_min = 15,
167 .cw_max = 63,
168 .aifsn = CONF_TX_AIFS_PIFS,
169 .tx_op_limit = 1504,
170 },
171 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300172 .max_tx_retries = 100,
173 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300175 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200176 [CONF_TX_AC_BE] = {
177 .queue_id = CONF_TX_AC_BE,
178 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300179 .tsid = CONF_TX_AC_BE,
180 .ps_scheme = CONF_PS_SCHEME_LEGACY,
181 .ack_policy = CONF_ACK_POLICY_LEGACY,
182 .apsd_conf = {0, 0},
183 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200184 [CONF_TX_AC_BK] = {
185 .queue_id = CONF_TX_AC_BK,
186 .channel_type = CONF_CHANNEL_TYPE_EDCF,
187 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300188 .ps_scheme = CONF_PS_SCHEME_LEGACY,
189 .ack_policy = CONF_ACK_POLICY_LEGACY,
190 .apsd_conf = {0, 0},
191 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200192 [CONF_TX_AC_VI] = {
193 .queue_id = CONF_TX_AC_VI,
194 .channel_type = CONF_CHANNEL_TYPE_EDCF,
195 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .ps_scheme = CONF_PS_SCHEME_LEGACY,
197 .ack_policy = CONF_ACK_POLICY_LEGACY,
198 .apsd_conf = {0, 0},
199 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200200 [CONF_TX_AC_VO] = {
201 .queue_id = CONF_TX_AC_VO,
202 .channel_type = CONF_CHANNEL_TYPE_EDCF,
203 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300204 .ps_scheme = CONF_PS_SCHEME_LEGACY,
205 .ack_policy = CONF_ACK_POLICY_LEGACY,
206 .apsd_conf = {0, 0},
207 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300208 },
209 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200210 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300211 .tx_compl_threshold = 4,
212 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
213 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200214 .tmpl_short_retry_limit = 10,
215 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300216 },
217 .conn = {
218 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300219 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300221 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300222 .bcn_filt_ie = {
223 [0] = {
224 .ie = WLAN_EID_CHANNEL_SWITCH,
225 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300226 },
227 [1] = {
228 .ie = WLAN_EID_HT_INFORMATION,
229 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
230 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200232 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 .bss_lose_timeout = 100,
234 .beacon_rx_timeout = 10000,
235 .broadcast_timeout = 20000,
236 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300237 .ps_poll_threshold = 10,
238 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300239 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200240 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300241 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300242 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200243 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300244 .keep_alive_interval = 55000,
245 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300246 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200247 .itrim = {
248 .enable = false,
249 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200250 },
251 .pm_config = {
252 .host_clk_settling_time = 5000,
253 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 },
255 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300256 .trigger_pacing = 1,
257 .avg_weight_rssi_beacon = 20,
258 .avg_weight_rssi_data = 10,
259 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100260 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200261 },
262 .scan = {
263 .min_dwell_time_active = 7500,
264 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100265 .min_dwell_time_passive = 100000,
266 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200267 .num_probe_reqs = 2,
268 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300269 .sched_scan = {
270 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300271 .min_dwell_time_active = 30,
272 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300274 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300275 .num_probe_reqs = 2,
276 .rssi_threshold = -90,
277 .snr_threshold = 0,
278 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200279 .rf = {
280 .tx_per_channel_power_compensation_2 = {
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 },
283 .tx_per_channel_power_compensation_5 = {
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 },
288 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300290 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100291 .tx_ba_win_size = 64,
292 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300293 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100294 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200295 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200296 .num_stations = 1,
297 .ssid_profiles = 1,
298 .rx_block_num = 70,
299 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300300 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200301 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200302 .min_req_rx_blocks = 22,
303 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200304 },
305 .mem_wl128x = {
306 .num_stations = 1,
307 .ssid_profiles = 1,
308 .rx_block_num = 40,
309 .tx_min_block_num = 40,
310 .dynamic_memory = 1,
311 .min_req_tx_blocks = 45,
312 .min_req_rx_blocks = 22,
313 .tx_min = 27,
314 },
Shahar Leviff868432011-04-11 15:41:46 +0300315 .fm_coex = {
316 .enable = true,
317 .swallow_period = 5,
318 .n_divider_fref_set_1 = 0xff, /* default */
319 .n_divider_fref_set_2 = 12,
320 .m_divider_fref_set_1 = 148,
321 .m_divider_fref_set_2 = 0xffff, /* default */
322 .coex_pll_stabilization_time = 0xffffffff, /* default */
323 .ldo_stabilization_time = 0xffff, /* default */
324 .fm_disturbed_band_margin = 0xff, /* default */
325 .swallow_clk_diff = 0xff, /* default */
326 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300327 .rx_streaming = {
328 .duration = 150,
329 .queues = 0x1,
330 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300331 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300332 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300333 .fwlog = {
334 .mode = WL12XX_FWLOG_ON_DEMAND,
335 .mem_blocks = 2,
336 .severity = 0,
337 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
338 .output = WL12XX_FWLOG_OUTPUT_HOST,
339 .threshold = 0,
340 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300341 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300342 .rate = {
343 .rate_retry_score = 32000,
344 .per_add = 8192,
345 .per_th1 = 2048,
346 .per_th2 = 4096,
347 .max_per = 8100,
348 .inverse_curiosity_factor = 5,
349 .tx_fail_low_th = 4,
350 .tx_fail_high_th = 10,
351 .per_alpha_shift = 4,
352 .per_add_shift = 13,
353 .per_beta1_shift = 10,
354 .per_beta2_shift = 8,
355 .rate_check_up = 2,
356 .rate_check_down = 12,
357 .rate_retry_policy = {
358 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00,
361 },
362 },
Eliad Peller94877752011-08-28 15:11:56 +0300363 .hangover = {
364 .recover_time = 0,
365 .hangover_period = 20,
366 .dynamic_mode = 1,
367 .early_termination_mode = 1,
368 .max_period = 20,
369 .min_period = 1,
370 .increase_delta = 1,
371 .decrease_delta = 2,
372 .quiet_time = 4,
373 .increase_time = 1,
374 .window_size = 16,
375 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300376};
377
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300379static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300380
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300381static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200382 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300383 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200384static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200385static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200386
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200387static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300388static LIST_HEAD(wl_list);
389
Eliad Pellerba8447f2011-10-10 10:13:00 +0200390static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
391 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300392{
393 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200394
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300395 if (operstate != IF_OPER_UP)
396 return 0;
397
Eliad Peller8181aec2011-10-10 10:13:04 +0200398 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300399 return 0;
400
Eliad Peller154da672011-10-05 11:55:53 +0200401 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300402 if (ret < 0)
403 return ret;
404
Eliad Peller0603d892011-10-05 11:55:51 +0200405 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300406
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300407 wl1271_info("Association completed.");
408 return 0;
409}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300410static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
411 void *arg)
412{
413 struct net_device *dev = arg;
414 struct wireless_dev *wdev;
415 struct wiphy *wiphy;
416 struct ieee80211_hw *hw;
417 struct wl1271 *wl;
418 struct wl1271 *wl_temp;
Eliad Pellerba8447f2011-10-10 10:13:00 +0200419 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300420 int ret = 0;
421
422 /* Check that this notification is for us. */
423 if (what != NETDEV_CHANGE)
424 return NOTIFY_DONE;
425
426 wdev = dev->ieee80211_ptr;
427 if (wdev == NULL)
428 return NOTIFY_DONE;
429
430 wiphy = wdev->wiphy;
431 if (wiphy == NULL)
432 return NOTIFY_DONE;
433
434 hw = wiphy_priv(wiphy);
435 if (hw == NULL)
436 return NOTIFY_DONE;
437
438 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200439 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300440 list_for_each_entry(wl, &wl_list, list) {
441 if (wl == wl_temp)
442 break;
443 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200444 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300445 if (wl != wl_temp)
446 return NOTIFY_DONE;
447
448 mutex_lock(&wl->mutex);
449
450 if (wl->state == WL1271_STATE_OFF)
451 goto out;
452
Eliad Peller6ab70912011-12-18 20:25:45 +0200453 if (dev->operstate != IF_OPER_UP)
454 goto out;
455 /*
456 * The correct behavior should be just getting the appropriate wlvif
457 * from the given dev, but currently we don't have a mac80211
458 * interface for it.
459 */
Eliad Pellerba8447f2011-10-10 10:13:00 +0200460 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller6ab70912011-12-18 20:25:45 +0200461 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
462
Eliad Pellerba8447f2011-10-10 10:13:00 +0200463 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
464 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300465
Eliad Pellerba8447f2011-10-10 10:13:00 +0200466 ret = wl1271_ps_elp_wakeup(wl);
467 if (ret < 0)
468 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300469
Eliad Peller6ab70912011-12-18 20:25:45 +0200470 wl1271_check_operstate(wl, wlvif,
471 ieee80211_get_operstate(vif));
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300472
Eliad Pellerba8447f2011-10-10 10:13:00 +0200473 wl1271_ps_elp_sleep(wl);
474 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300475out:
476 mutex_unlock(&wl->mutex);
477
478 return NOTIFY_OK;
479}
480
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100481static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200482 struct regulatory_request *request)
483{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100484 struct ieee80211_supported_band *band;
485 struct ieee80211_channel *ch;
486 int i;
487
488 band = wiphy->bands[IEEE80211_BAND_5GHZ];
489 for (i = 0; i < band->n_channels; i++) {
490 ch = &band->channels[i];
491 if (ch->flags & IEEE80211_CHAN_DISABLED)
492 continue;
493
494 if (ch->flags & IEEE80211_CHAN_RADAR)
495 ch->flags |= IEEE80211_CHAN_NO_IBSS |
496 IEEE80211_CHAN_PASSIVE_SCAN;
497
498 }
499
500 return 0;
501}
502
Eliad Peller9eb599e2011-10-10 10:12:59 +0200503static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
504 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300505{
506 int ret = 0;
507
508 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200509 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300510 if (ret < 0)
511 goto out;
512
513 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200514 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300515 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200516 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300517out:
518 return ret;
519}
520
521/*
522 * this function is being called when the rx_streaming interval
523 * has beed changed or rx_streaming should be disabled
524 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200525int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300526{
527 int ret = 0;
528 int period = wl->conf.rx_streaming.interval;
529
530 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200531 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300532 goto out;
533
534 /* reconfigure/disable according to new streaming_period */
535 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200536 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300537 (wl->conf.rx_streaming.always ||
538 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200539 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300540 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200541 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300542 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200543 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300544 }
545out:
546 return ret;
547}
548
549static void wl1271_rx_streaming_enable_work(struct work_struct *work)
550{
551 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200552 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
553 rx_streaming_enable_work);
554 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300555
556 mutex_lock(&wl->mutex);
557
Eliad Peller0744bdb2011-10-10 10:13:05 +0200558 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200559 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300560 (!wl->conf.rx_streaming.always &&
561 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
562 goto out;
563
564 if (!wl->conf.rx_streaming.interval)
565 goto out;
566
567 ret = wl1271_ps_elp_wakeup(wl);
568 if (ret < 0)
569 goto out;
570
Eliad Peller9eb599e2011-10-10 10:12:59 +0200571 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300572 if (ret < 0)
573 goto out_sleep;
574
575 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200576 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300577 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
578
579out_sleep:
580 wl1271_ps_elp_sleep(wl);
581out:
582 mutex_unlock(&wl->mutex);
583}
584
585static void wl1271_rx_streaming_disable_work(struct work_struct *work)
586{
587 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200588 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
589 rx_streaming_disable_work);
590 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300591
592 mutex_lock(&wl->mutex);
593
Eliad Peller0744bdb2011-10-10 10:13:05 +0200594 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300595 goto out;
596
597 ret = wl1271_ps_elp_wakeup(wl);
598 if (ret < 0)
599 goto out;
600
Eliad Peller9eb599e2011-10-10 10:12:59 +0200601 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300602 if (ret)
603 goto out_sleep;
604
605out_sleep:
606 wl1271_ps_elp_sleep(wl);
607out:
608 mutex_unlock(&wl->mutex);
609}
610
611static void wl1271_rx_streaming_timer(unsigned long data)
612{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200613 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
614 struct wl1271 *wl = wlvif->wl;
615 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300616}
617
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300618static void wl1271_conf_init(struct wl1271 *wl)
619{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300620
621 /*
622 * This function applies the default configuration to the driver. This
623 * function is invoked upon driver load (spi probe.)
624 *
625 * The configuration is stored in a run-time structure in order to
626 * facilitate for run-time adjustment of any of the parameters. Making
627 * changes to the configuration structure will apply the new values on
628 * the next interface up (wl1271_op_start.)
629 */
630
631 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300632 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300633
Ido Yariv95dac04f2011-06-06 14:57:06 +0300634 /* Adjust settings according to optional module parameters */
635 if (fwlog_param) {
636 if (!strcmp(fwlog_param, "continuous")) {
637 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
638 } else if (!strcmp(fwlog_param, "ondemand")) {
639 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
640 } else if (!strcmp(fwlog_param, "dbgpins")) {
641 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
642 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
643 } else if (!strcmp(fwlog_param, "disable")) {
644 wl->conf.fwlog.mem_blocks = 0;
645 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
646 } else {
647 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
648 }
649 }
650}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300651
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300652static int wl1271_plt_init(struct wl1271 *wl)
653{
Eliad Peller188e7f52011-12-06 12:15:06 +0200654 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300655
Shahar Levi49d750ca2011-03-06 16:32:09 +0200656 if (wl->chip.id == CHIP_ID_1283_PG20)
657 ret = wl128x_cmd_general_parms(wl);
658 else
659 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200660 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200661 return ret;
662
Shahar Levi49d750ca2011-03-06 16:32:09 +0200663 if (wl->chip.id == CHIP_ID_1283_PG20)
664 ret = wl128x_cmd_radio_parms(wl);
665 else
666 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200667 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200668 return ret;
669
Shahar Levi49d750ca2011-03-06 16:32:09 +0200670 if (wl->chip.id != CHIP_ID_1283_PG20) {
671 ret = wl1271_cmd_ext_radio_parms(wl);
672 if (ret < 0)
673 return ret;
674 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200675 if (ret < 0)
676 return ret;
677
Shahar Levi48a61472011-03-06 16:32:08 +0200678 /* Chip-specific initializations */
679 ret = wl1271_chip_specific_init(wl);
680 if (ret < 0)
681 return ret;
682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 ret = wl1271_acx_init_mem_config(wl);
684 if (ret < 0)
685 return ret;
686
Eliad Peller7f0979882011-08-14 13:17:06 +0300687 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600688 if (ret < 0)
689 goto out_free_memmap;
690
Luciano Coelho12419cc2010-02-18 13:25:44 +0200691 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200692 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300693 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200694 goto out_free_memmap;
695
696 /* Configure for CAM power saving (ie. always active) */
697 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
698 if (ret < 0)
699 goto out_free_memmap;
700
701 /* configure PM */
702 ret = wl1271_acx_pm_config(wl);
703 if (ret < 0)
704 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300705
706 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200707
708 out_free_memmap:
709 kfree(wl->target_mem_map);
710 wl->target_mem_map = NULL;
711
712 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713}
714
Eliad Peller6e8cd332011-10-10 10:13:13 +0200715static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
716 struct wl12xx_vif *wlvif,
717 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200718{
Arik Nemtsovda032092011-08-25 12:43:15 +0300719 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200720
Arik Nemtsovb622d992011-02-23 00:22:31 +0200721 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300722 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200723
724 /*
725 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300726 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200727 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300728 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200729 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200730
Arik Nemtsovda032092011-08-25 12:43:15 +0300731 /*
732 * Start high-level PS if the STA is asleep with enough blocks in FW.
733 * Make an exception if this is the only connected station. In this
734 * case FW-memory congestion is not a problem.
735 */
736 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200737 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200738}
739
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300740static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200741 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300742 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200743{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200744 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200745 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300746 u8 hlid, cnt;
747
748 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200749
750 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
751 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
752 wl1271_debug(DEBUG_PSM,
753 "link ps prev 0x%x cur 0x%x changed 0x%x",
754 wl->ap_fw_ps_map, cur_fw_ps_map,
755 wl->ap_fw_ps_map ^ cur_fw_ps_map);
756
757 wl->ap_fw_ps_map = cur_fw_ps_map;
758 }
759
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200760 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
761 lnk = &wl->links[hlid];
762 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200763
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200764 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
765 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200766
Eliad Peller6e8cd332011-10-10 10:13:13 +0200767 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
768 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200769 }
770}
771
Eliad Peller4d56ad92011-08-14 13:17:05 +0300772static void wl12xx_fw_status(struct wl1271 *wl,
773 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300774{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200775 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200776 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200777 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300778 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300779 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300780
Eliad Peller4d56ad92011-08-14 13:17:05 +0300781 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200782
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300783 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
784 "drv_rx_counter = %d, tx_results_counter = %d)",
785 status->intr,
786 status->fw_rx_counter,
787 status->drv_rx_counter,
788 status->tx_results_counter);
789
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300790 for (i = 0; i < NUM_TX_QUEUES; i++) {
791 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300792 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300793 (status->tx_released_pkts[i] -
794 wl->tx_pkts_freed[i]) & 0xff;
795
796 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
797 }
798
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300799 /* prevent wrap-around in total blocks counter */
800 if (likely(wl->tx_blocks_freed <=
801 le32_to_cpu(status->total_released_blks)))
802 freed_blocks = le32_to_cpu(status->total_released_blks) -
803 wl->tx_blocks_freed;
804 else
805 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
806 le32_to_cpu(status->total_released_blks);
807
Eliad Peller4d56ad92011-08-14 13:17:05 +0300808 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200809
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300810 wl->tx_allocated_blocks -= freed_blocks;
811
Eliad Peller4d56ad92011-08-14 13:17:05 +0300812 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200813
Eliad Peller4d56ad92011-08-14 13:17:05 +0300814 /*
815 * The FW might change the total number of TX memblocks before
816 * we get a notification about blocks being released. Thus, the
817 * available blocks calculation might yield a temporary result
818 * which is lower than the actual available blocks. Keeping in
819 * mind that only blocks that were allocated can be moved from
820 * TX to RX, tx_blocks_available should never decrease here.
821 */
822 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
823 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300824
Ido Yariva5225502010-10-12 14:49:10 +0200825 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200826 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200827 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828
Eliad Peller4d56ad92011-08-14 13:17:05 +0300829 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200830 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200831 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200832 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300833
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200835 getnstimeofday(&ts);
836 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
837 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300838}
839
Ido Yariva6208652011-03-01 15:14:41 +0200840static void wl1271_flush_deferred_work(struct wl1271 *wl)
841{
842 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200843
Ido Yariva6208652011-03-01 15:14:41 +0200844 /* Pass all received frames to the network stack */
845 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
846 ieee80211_rx_ni(wl->hw, skb);
847
848 /* Return sent skbs to the network stack */
849 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300850 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200851}
852
853static void wl1271_netstack_work(struct work_struct *work)
854{
855 struct wl1271 *wl =
856 container_of(work, struct wl1271, netstack_work);
857
858 do {
859 wl1271_flush_deferred_work(wl);
860 } while (skb_queue_len(&wl->deferred_rx_queue));
861}
862
863#define WL1271_IRQ_MAX_LOOPS 256
864
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300865static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300866{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300867 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300868 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200869 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200870 struct wl1271 *wl = (struct wl1271 *)cookie;
871 bool done = false;
872 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200873 unsigned long flags;
874
875 /* TX might be handled here, avoid redundant work */
876 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
877 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878
Ido Yariv341b7cd2011-03-31 10:07:01 +0200879 /*
880 * In case edge triggered interrupt must be used, we cannot iterate
881 * more than once without introducing race conditions with the hardirq.
882 */
883 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
884 loopcount = 1;
885
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300886 mutex_lock(&wl->mutex);
887
888 wl1271_debug(DEBUG_IRQ, "IRQ work");
889
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200890 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300891 goto out;
892
Ido Yariva6208652011-03-01 15:14:41 +0200893 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300894 if (ret < 0)
895 goto out;
896
Ido Yariva6208652011-03-01 15:14:41 +0200897 while (!done && loopcount--) {
898 /*
899 * In order to avoid a race with the hardirq, clear the flag
900 * before acknowledging the chip. Since the mutex is held,
901 * wl1271_ps_elp_wakeup cannot be called concurrently.
902 */
903 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
904 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200905
Eliad Peller4d56ad92011-08-14 13:17:05 +0300906 wl12xx_fw_status(wl, wl->fw_status);
907 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200908 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200909 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200910 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200911 continue;
912 }
913
Eliad Pellerccc83b02010-10-27 14:09:57 +0200914 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
915 wl1271_error("watchdog interrupt received! "
916 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300917 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200918
919 /* restarting the chip. ignore any other interrupt. */
920 goto out;
921 }
922
Ido Yariva6208652011-03-01 15:14:41 +0200923 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200924 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
925
Eliad Peller4d56ad92011-08-14 13:17:05 +0300926 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200927
Ido Yariva5225502010-10-12 14:49:10 +0200928 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200929 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200930 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300931 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200932 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200933 /*
934 * In order to avoid starvation of the TX path,
935 * call the work function directly.
936 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200937 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200938 } else {
939 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200940 }
941
Ido Yariv8aad2462011-03-01 15:14:38 +0200942 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300943 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200944 (wl->tx_results_count & 0xff))
945 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200946
947 /* Make sure the deferred queues don't get too long */
948 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
949 skb_queue_len(&wl->deferred_rx_queue);
950 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
951 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200952 }
953
954 if (intr & WL1271_ACX_INTR_EVENT_A) {
955 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
956 wl1271_event_handle(wl, 0);
957 }
958
959 if (intr & WL1271_ACX_INTR_EVENT_B) {
960 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
961 wl1271_event_handle(wl, 1);
962 }
963
964 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
965 wl1271_debug(DEBUG_IRQ,
966 "WL1271_ACX_INTR_INIT_COMPLETE");
967
968 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
969 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970 }
971
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972 wl1271_ps_elp_sleep(wl);
973
974out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200975 spin_lock_irqsave(&wl->wl_lock, flags);
976 /* In case TX was not handled here, queue TX work */
977 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
978 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300979 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200980 ieee80211_queue_work(wl->hw, &wl->tx_work);
981 spin_unlock_irqrestore(&wl->wl_lock, flags);
982
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200984
985 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300986}
987
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988static int wl1271_fetch_firmware(struct wl1271 *wl)
989{
990 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200991 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300992 int ret;
993
Arik Nemtsovc302b2c2011-08-17 10:45:48 +0300994 if (wl->chip.id == CHIP_ID_1283_PG20)
995 fw_name = WL128X_FW_NAME;
996 else
997 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200998
999 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1000
Felipe Balbia390e852011-10-06 10:07:44 +03001001 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001002
1003 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001004 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001005 return ret;
1006 }
1007
1008 if (fw->size % 4) {
1009 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1010 fw->size);
1011 ret = -EILSEQ;
1012 goto out;
1013 }
1014
Arik Nemtsov166d5042010-10-16 21:44:57 +02001015 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001017 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018
1019 if (!wl->fw) {
1020 wl1271_error("could not allocate memory for the firmware");
1021 ret = -ENOMEM;
1022 goto out;
1023 }
1024
1025 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026 ret = 0;
1027
1028out:
1029 release_firmware(fw);
1030
1031 return ret;
1032}
1033
1034static int wl1271_fetch_nvs(struct wl1271 *wl)
1035{
1036 const struct firmware *fw;
1037 int ret;
1038
Felipe Balbia390e852011-10-06 10:07:44 +03001039 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040
1041 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001042 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
1043 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001044 return ret;
1045 }
1046
Shahar Levibc765bf2011-03-06 16:32:10 +02001047 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048
1049 if (!wl->nvs) {
1050 wl1271_error("could not allocate memory for the nvs file");
1051 ret = -ENOMEM;
1052 goto out;
1053 }
1054
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001055 wl->nvs_len = fw->size;
1056
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057out:
1058 release_firmware(fw);
1059
1060 return ret;
1061}
1062
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001063void wl12xx_queue_recovery_work(struct wl1271 *wl)
1064{
1065 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1066 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1067}
1068
Ido Yariv95dac04f2011-06-06 14:57:06 +03001069size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1070{
1071 size_t len = 0;
1072
1073 /* The FW log is a length-value list, find where the log end */
1074 while (len < maxlen) {
1075 if (memblock[len] == 0)
1076 break;
1077 if (len + memblock[len] + 1 > maxlen)
1078 break;
1079 len += memblock[len] + 1;
1080 }
1081
1082 /* Make sure we have enough room */
1083 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1084
1085 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1086 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1087 wl->fwlog_size += len;
1088
1089 return len;
1090}
1091
1092static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1093{
1094 u32 addr;
1095 u32 first_addr;
1096 u8 *block;
1097
1098 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1099 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1100 (wl->conf.fwlog.mem_blocks == 0))
1101 return;
1102
1103 wl1271_info("Reading FW panic log");
1104
1105 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1106 if (!block)
1107 return;
1108
1109 /*
1110 * Make sure the chip is awake and the logger isn't active.
1111 * This might fail if the firmware hanged.
1112 */
1113 if (!wl1271_ps_elp_wakeup(wl))
1114 wl12xx_cmd_stop_fwlog(wl);
1115
1116 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001117 wl12xx_fw_status(wl, wl->fw_status);
1118 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001119 if (!first_addr)
1120 goto out;
1121
1122 /* Traverse the memory blocks linked list */
1123 addr = first_addr;
1124 do {
1125 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1126 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1127 false);
1128
1129 /*
1130 * Memory blocks are linked to one another. The first 4 bytes
1131 * of each memory block hold the hardware address of the next
1132 * one. The last memory block points to the first one.
1133 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001134 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001135 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1136 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1137 break;
1138 } while (addr && (addr != first_addr));
1139
1140 wake_up_interruptible(&wl->fwlog_waitq);
1141
1142out:
1143 kfree(block);
1144}
1145
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001146static void wl1271_recovery_work(struct work_struct *work)
1147{
1148 struct wl1271 *wl =
1149 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001150 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001151 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001152
1153 mutex_lock(&wl->mutex);
1154
1155 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001156 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001157
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001158 /* Avoid a recursive recovery */
1159 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1160
Ido Yariv95dac04f2011-06-06 14:57:06 +03001161 wl12xx_read_fwlog_panic(wl);
1162
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001163 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1164 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001165
Eliad Peller2a5bff02011-08-25 18:10:59 +03001166 BUG_ON(bug_on_recovery);
1167
Oz Krakowskib992c682011-06-26 10:36:02 +03001168 /*
1169 * Advance security sequence number to overcome potential progress
1170 * in the firmware during recovery. This doens't hurt if the network is
1171 * not encrypted.
1172 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001173 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001174 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001175 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001176 wlvif->tx_security_seq +=
1177 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1178 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001179
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001180 /* Prevent spurious TX during FW restart */
1181 ieee80211_stop_queues(wl->hw);
1182
Luciano Coelho33c2c062011-05-10 14:46:02 +03001183 if (wl->sched_scanning) {
1184 ieee80211_sched_scan_stopped(wl->hw);
1185 wl->sched_scanning = false;
1186 }
1187
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001188 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001189 while (!list_empty(&wl->wlvif_list)) {
1190 wlvif = list_first_entry(&wl->wlvif_list,
1191 struct wl12xx_vif, list);
1192 vif = wl12xx_wlvif_to_vif(wlvif);
1193 __wl1271_op_remove_interface(wl, vif, false);
1194 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001195 mutex_unlock(&wl->mutex);
1196 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001197
1198 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1199
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001200 ieee80211_restart_hw(wl->hw);
1201
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001202 /*
1203 * Its safe to enable TX now - the queues are stopped after a request
1204 * to restart the HW.
1205 */
1206 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001207 return;
1208out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001209 mutex_unlock(&wl->mutex);
1210}
1211
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001212static void wl1271_fw_wakeup(struct wl1271 *wl)
1213{
1214 u32 elp_reg;
1215
1216 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001217 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218}
1219
1220static int wl1271_setup(struct wl1271 *wl)
1221{
1222 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1223 if (!wl->fw_status)
1224 return -ENOMEM;
1225
1226 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1227 if (!wl->tx_res_if) {
1228 kfree(wl->fw_status);
1229 return -ENOMEM;
1230 }
1231
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001232 return 0;
1233}
1234
1235static int wl1271_chip_wakeup(struct wl1271 *wl)
1236{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001237 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001238 int ret = 0;
1239
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001240 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001241 ret = wl1271_power_on(wl);
1242 if (ret < 0)
1243 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001244 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001245 wl1271_io_reset(wl);
1246 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247
1248 /* We don't need a real memory partition here, because we only want
1249 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001250 memset(&partition, 0, sizeof(partition));
1251 partition.reg.start = REGISTERS_BASE;
1252 partition.reg.size = REGISTERS_DOWN_SIZE;
1253 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254
1255 /* ELP module wake up */
1256 wl1271_fw_wakeup(wl);
1257
1258 /* whal_FwCtrl_BootSm() */
1259
1260 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001261 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001262
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001263 /*
1264 * For wl127x based devices we could use the default block
1265 * size (512 bytes), but due to a bug in the sdio driver, we
1266 * need to set it explicitly after the chip is powered on. To
1267 * simplify the code and since the performance impact is
1268 * negligible, we use the same block size for all different
1269 * chip types.
1270 */
1271 if (!wl1271_set_block_size(wl))
1272 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273
1274 switch (wl->chip.id) {
1275 case CHIP_ID_1271_PG10:
1276 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1277 wl->chip.id);
1278
1279 ret = wl1271_setup(wl);
1280 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001281 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001282 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001284
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 case CHIP_ID_1271_PG20:
1286 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1287 wl->chip.id);
1288
1289 ret = wl1271_setup(wl);
1290 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001291 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001292 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001293 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001294
Shahar Levi0830cee2011-03-06 16:32:20 +02001295 case CHIP_ID_1283_PG20:
1296 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1297 wl->chip.id);
1298
1299 ret = wl1271_setup(wl);
1300 if (ret < 0)
1301 goto out;
1302 break;
1303 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001304 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001305 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001307 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001308 }
1309
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001310 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001311 ret = wl1271_fetch_firmware(wl);
1312 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001313 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314 }
1315
1316 /* No NVS from netlink, try to get it from the filesystem */
1317 if (wl->nvs == NULL) {
1318 ret = wl1271_fetch_nvs(wl);
1319 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001320 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321 }
1322
1323out:
1324 return ret;
1325}
1326
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327int wl1271_plt_start(struct wl1271 *wl)
1328{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001329 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001330 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331 int ret;
1332
1333 mutex_lock(&wl->mutex);
1334
1335 wl1271_notice("power up");
1336
1337 if (wl->state != WL1271_STATE_OFF) {
1338 wl1271_error("cannot go into PLT state because not "
1339 "in off state: %d", wl->state);
1340 ret = -EBUSY;
1341 goto out;
1342 }
1343
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001344 while (retries) {
1345 retries--;
1346 ret = wl1271_chip_wakeup(wl);
1347 if (ret < 0)
1348 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001349
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001350 ret = wl1271_boot(wl);
1351 if (ret < 0)
1352 goto power_off;
1353
1354 ret = wl1271_plt_init(wl);
1355 if (ret < 0)
1356 goto irq_disable;
1357
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001358 wl->state = WL1271_STATE_PLT;
1359 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001360 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001361
Gery Kahn6f07b722011-07-18 14:21:49 +03001362 /* update hw/fw version info in wiphy struct */
1363 wiphy->hw_version = wl->chip.id;
1364 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1365 sizeof(wiphy->fw_version));
1366
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367 goto out;
1368
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001369irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001370 mutex_unlock(&wl->mutex);
1371 /* Unlocking the mutex in the middle of handling is
1372 inherently unsafe. In this case we deem it safe to do,
1373 because we need to let any possibly pending IRQ out of
1374 the system (and while we are WL1271_STATE_OFF the IRQ
1375 work function will not do anything.) Also, any other
1376 possible concurrent operations will fail due to the
1377 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001378 wl1271_disable_interrupts(wl);
1379 wl1271_flush_deferred_work(wl);
1380 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001381 mutex_lock(&wl->mutex);
1382power_off:
1383 wl1271_power_off(wl);
1384 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001386 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1387 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001388out:
1389 mutex_unlock(&wl->mutex);
1390
1391 return ret;
1392}
1393
Luciano Coelho4623ec72011-03-21 19:26:41 +02001394static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001395{
1396 int ret = 0;
1397
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001398 wl1271_notice("power down");
1399
1400 if (wl->state != WL1271_STATE_PLT) {
1401 wl1271_error("cannot power down because not in PLT "
1402 "state: %d", wl->state);
1403 ret = -EBUSY;
1404 goto out;
1405 }
1406
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407 wl1271_power_off(wl);
1408
1409 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001410 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001411
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001412 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001413 wl1271_disable_interrupts(wl);
1414 wl1271_flush_deferred_work(wl);
1415 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001416 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001417 mutex_lock(&wl->mutex);
1418out:
1419 return ret;
1420}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001421
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001422int wl1271_plt_stop(struct wl1271 *wl)
1423{
1424 int ret;
1425
1426 mutex_lock(&wl->mutex);
1427 ret = __wl1271_plt_stop(wl);
1428 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429 return ret;
1430}
1431
Johannes Berg7bb45682011-02-24 14:42:06 +01001432static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001433{
1434 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001435 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1436 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001437 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001438 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001439 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001440 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441
Eliad Peller0f168012011-10-11 13:52:25 +02001442 if (vif)
1443 wlvif = wl12xx_vif_to_data(vif);
1444
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001445 mapping = skb_get_queue_mapping(skb);
1446 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001447
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001448 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001449
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001450 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001451
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001452 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001453 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001454 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001455 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001456 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001457 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001458 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001459
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001460 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1461 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1462
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001463 wl->tx_queue_count[q]++;
1464
1465 /*
1466 * The workqueue is slow to process the tx_queue and we need stop
1467 * the queue here, otherwise the queue will get too long.
1468 */
1469 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1470 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1471 ieee80211_stop_queue(wl->hw, mapping);
1472 set_bit(q, &wl->stopped_queues_map);
1473 }
1474
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001475 /*
1476 * The chip specific setup must run before the first TX packet -
1477 * before that, the tx_work will not be initialized!
1478 */
1479
Ido Yarivb07d4032011-03-01 15:14:43 +02001480 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1481 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001482 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001483
Arik Nemtsov04216da2011-08-14 13:17:38 +03001484out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001485 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486}
1487
Shahar Leviae47c452011-03-06 16:32:14 +02001488int wl1271_tx_dummy_packet(struct wl1271 *wl)
1489{
Ido Yariv990f5de2011-03-31 10:06:59 +02001490 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001491 int q;
1492
1493 /* no need to queue a new dummy packet if one is already pending */
1494 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1495 return 0;
1496
1497 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001498
Ido Yariv990f5de2011-03-31 10:06:59 +02001499 spin_lock_irqsave(&wl->wl_lock, flags);
1500 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001501 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001502 spin_unlock_irqrestore(&wl->wl_lock, flags);
1503
1504 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1505 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001506 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001507
1508 /*
1509 * If the FW TX is busy, TX work will be scheduled by the threaded
1510 * interrupt handler function
1511 */
1512 return 0;
1513}
1514
1515/*
1516 * The size of the dummy packet should be at least 1400 bytes. However, in
1517 * order to minimize the number of bus transactions, aligning it to 512 bytes
1518 * boundaries could be beneficial, performance wise
1519 */
1520#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1521
Luciano Coelhocf27d862011-04-01 21:08:23 +03001522static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001523{
1524 struct sk_buff *skb;
1525 struct ieee80211_hdr_3addr *hdr;
1526 unsigned int dummy_packet_size;
1527
1528 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1529 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1530
1531 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001532 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001533 wl1271_warning("Failed to allocate a dummy packet skb");
1534 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001535 }
1536
1537 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1538
1539 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1540 memset(hdr, 0, sizeof(*hdr));
1541 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001542 IEEE80211_STYPE_NULLFUNC |
1543 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001544
Ido Yariv990f5de2011-03-31 10:06:59 +02001545 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001546
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001547 /* Dummy packets require the TID to be management */
1548 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001549
1550 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001551 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001552 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001553
Ido Yariv990f5de2011-03-31 10:06:59 +02001554 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001555}
1556
Ido Yariv990f5de2011-03-31 10:06:59 +02001557
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001558static struct notifier_block wl1271_dev_notifier = {
1559 .notifier_call = wl1271_dev_notify,
1560};
1561
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001562#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001563static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1564 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001565{
Eliad Pellere85d1622011-06-27 13:06:43 +03001566 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001567
Eliad Peller94390642011-05-13 11:57:13 +03001568 mutex_lock(&wl->mutex);
1569
Eliad Pellerba8447f2011-10-10 10:13:00 +02001570 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001571 goto out_unlock;
1572
Eliad Peller94390642011-05-13 11:57:13 +03001573 ret = wl1271_ps_elp_wakeup(wl);
1574 if (ret < 0)
1575 goto out_unlock;
1576
1577 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001578 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001579 DECLARE_COMPLETION_ONSTACK(compl);
1580
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001581 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001582 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001583 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001584 if (ret < 0)
1585 goto out_sleep;
1586
1587 /* we must unlock here so we will be able to get events */
1588 wl1271_ps_elp_sleep(wl);
1589 mutex_unlock(&wl->mutex);
1590
1591 ret = wait_for_completion_timeout(
1592 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
Pontus Fuchsef187062011-12-14 14:32:23 +01001593
1594 mutex_lock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001595 if (ret <= 0) {
1596 wl1271_warning("couldn't enter ps mode!");
1597 ret = -EBUSY;
Pontus Fuchsef187062011-12-14 14:32:23 +01001598 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001599 }
1600
Eliad Peller94390642011-05-13 11:57:13 +03001601 ret = wl1271_ps_elp_wakeup(wl);
1602 if (ret < 0)
Pontus Fuchsef187062011-12-14 14:32:23 +01001603 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001604 }
1605out_sleep:
1606 wl1271_ps_elp_sleep(wl);
Pontus Fuchsef187062011-12-14 14:32:23 +01001607out_cleanup:
1608 wlvif->ps_compl = NULL;
Eliad Peller94390642011-05-13 11:57:13 +03001609out_unlock:
1610 mutex_unlock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001611 return ret;
1612
1613}
1614
Eliad Peller0603d892011-10-05 11:55:51 +02001615static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1616 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001617{
Eliad Pellere85d1622011-06-27 13:06:43 +03001618 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001619
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001620 mutex_lock(&wl->mutex);
1621
Eliad Peller53d40d02011-10-10 10:13:02 +02001622 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001623 goto out_unlock;
1624
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001625 ret = wl1271_ps_elp_wakeup(wl);
1626 if (ret < 0)
1627 goto out_unlock;
1628
Eliad Peller0603d892011-10-05 11:55:51 +02001629 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001630
1631 wl1271_ps_elp_sleep(wl);
1632out_unlock:
1633 mutex_unlock(&wl->mutex);
1634 return ret;
1635
1636}
1637
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001638static int wl1271_configure_suspend(struct wl1271 *wl,
1639 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001640{
Eliad Peller536129c2011-10-05 11:55:45 +02001641 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001642 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001643 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001644 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001645 return 0;
1646}
1647
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001648static void wl1271_configure_resume(struct wl1271 *wl,
1649 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001650{
1651 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001652 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1653 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001654
1655 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001656 return;
1657
1658 mutex_lock(&wl->mutex);
1659 ret = wl1271_ps_elp_wakeup(wl);
1660 if (ret < 0)
1661 goto out;
1662
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001663 if (is_sta) {
1664 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001665 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001666 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001667 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001668 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001669 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001670 }
Eliad Peller94390642011-05-13 11:57:13 +03001671
1672 wl1271_ps_elp_sleep(wl);
1673out:
1674 mutex_unlock(&wl->mutex);
1675}
1676
Eliad Peller402e48612011-05-13 11:57:09 +03001677static int wl1271_op_suspend(struct ieee80211_hw *hw,
1678 struct cfg80211_wowlan *wow)
1679{
1680 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001681 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001682 int ret;
1683
Eliad Peller402e48612011-05-13 11:57:09 +03001684 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001685 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001686
Eliad Peller4a859df2011-06-06 12:21:52 +03001687 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001688 wl12xx_for_each_wlvif(wl, wlvif) {
1689 ret = wl1271_configure_suspend(wl, wlvif);
1690 if (ret < 0) {
1691 wl1271_warning("couldn't prepare device to suspend");
1692 return ret;
1693 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001694 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001695 /* flush any remaining work */
1696 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001697
1698 /*
1699 * disable and re-enable interrupts in order to flush
1700 * the threaded_irq
1701 */
1702 wl1271_disable_interrupts(wl);
1703
1704 /*
1705 * set suspended flag to avoid triggering a new threaded_irq
1706 * work. no need for spinlock as interrupts are disabled.
1707 */
1708 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1709
1710 wl1271_enable_interrupts(wl);
1711 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001712 wl12xx_for_each_wlvif(wl, wlvif) {
1713 flush_delayed_work(&wlvif->pspoll_work);
1714 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001715 flush_delayed_work(&wl->elp_work);
1716
Eliad Peller402e48612011-05-13 11:57:09 +03001717 return 0;
1718}
1719
1720static int wl1271_op_resume(struct ieee80211_hw *hw)
1721{
1722 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001723 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001724 unsigned long flags;
1725 bool run_irq_work = false;
1726
Eliad Peller402e48612011-05-13 11:57:09 +03001727 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1728 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001729 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001730
1731 /*
1732 * re-enable irq_work enqueuing, and call irq_work directly if
1733 * there is a pending work.
1734 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001735 spin_lock_irqsave(&wl->wl_lock, flags);
1736 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1737 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1738 run_irq_work = true;
1739 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001740
Eliad Peller4a859df2011-06-06 12:21:52 +03001741 if (run_irq_work) {
1742 wl1271_debug(DEBUG_MAC80211,
1743 "run postponed irq_work directly");
1744 wl1271_irq(0, wl);
1745 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001746 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001747 wl12xx_for_each_wlvif(wl, wlvif) {
1748 wl1271_configure_resume(wl, wlvif);
1749 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001750 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001751
Eliad Peller402e48612011-05-13 11:57:09 +03001752 return 0;
1753}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001754#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001755
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001756static int wl1271_op_start(struct ieee80211_hw *hw)
1757{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001758 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1759
1760 /*
1761 * We have to delay the booting of the hardware because
1762 * we need to know the local MAC address before downloading and
1763 * initializing the firmware. The MAC address cannot be changed
1764 * after boot, and without the proper MAC address, the firmware
1765 * will not function properly.
1766 *
1767 * The MAC address is first known when the corresponding interface
1768 * is added. That is where we will initialize the hardware.
1769 */
1770
1771 return 0;
1772}
1773
1774static void wl1271_op_stop(struct ieee80211_hw *hw)
1775{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001776 struct wl1271 *wl = hw->priv;
1777 int i;
1778
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001779 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001780
Eliad Peller10c8cd02011-10-10 10:13:06 +02001781 mutex_lock(&wl->mutex);
1782 if (wl->state == WL1271_STATE_OFF) {
1783 mutex_unlock(&wl->mutex);
1784 return;
1785 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001786 /*
1787 * this must be before the cancel_work calls below, so that the work
1788 * functions don't perform further work.
1789 */
1790 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001791 mutex_unlock(&wl->mutex);
1792
1793 mutex_lock(&wl_list_mutex);
1794 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001795 mutex_unlock(&wl_list_mutex);
1796
1797 wl1271_disable_interrupts(wl);
1798 wl1271_flush_deferred_work(wl);
1799 cancel_delayed_work_sync(&wl->scan_complete_work);
1800 cancel_work_sync(&wl->netstack_work);
1801 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001802 cancel_delayed_work_sync(&wl->elp_work);
1803
1804 /* let's notify MAC80211 about the remaining pending TX frames */
1805 wl12xx_tx_reset(wl, true);
1806 mutex_lock(&wl->mutex);
1807
1808 wl1271_power_off(wl);
1809
1810 wl->band = IEEE80211_BAND_2GHZ;
1811
1812 wl->rx_counter = 0;
1813 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1814 wl->tx_blocks_available = 0;
1815 wl->tx_allocated_blocks = 0;
1816 wl->tx_results_count = 0;
1817 wl->tx_packets_count = 0;
1818 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001819 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1820 wl->ap_fw_ps_map = 0;
1821 wl->ap_ps_map = 0;
1822 wl->sched_scanning = false;
1823 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1824 memset(wl->links_map, 0, sizeof(wl->links_map));
1825 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1826 wl->active_sta_count = 0;
1827
1828 /* The system link is always allocated */
1829 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1830
1831 /*
1832 * this is performed after the cancel_work calls and the associated
1833 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1834 * get executed before all these vars have been reset.
1835 */
1836 wl->flags = 0;
1837
1838 wl->tx_blocks_freed = 0;
1839
1840 for (i = 0; i < NUM_TX_QUEUES; i++) {
1841 wl->tx_pkts_freed[i] = 0;
1842 wl->tx_allocated_pkts[i] = 0;
1843 }
1844
1845 wl1271_debugfs_reset(wl);
1846
1847 kfree(wl->fw_status);
1848 wl->fw_status = NULL;
1849 kfree(wl->tx_res_if);
1850 wl->tx_res_if = NULL;
1851 kfree(wl->target_mem_map);
1852 wl->target_mem_map = NULL;
1853
1854 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001855}
1856
Eliad Pellere5a359f2011-10-10 10:13:15 +02001857static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1858{
1859 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1860 WL12XX_MAX_RATE_POLICIES);
1861 if (policy >= WL12XX_MAX_RATE_POLICIES)
1862 return -EBUSY;
1863
1864 __set_bit(policy, wl->rate_policies_map);
1865 *idx = policy;
1866 return 0;
1867}
1868
1869static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1870{
1871 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1872 return;
1873
1874 __clear_bit(*idx, wl->rate_policies_map);
1875 *idx = WL12XX_MAX_RATE_POLICIES;
1876}
1877
Eliad Peller536129c2011-10-05 11:55:45 +02001878static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001879{
Eliad Peller536129c2011-10-05 11:55:45 +02001880 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001881 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001882 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001883 return WL1271_ROLE_P2P_GO;
1884 else
1885 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001886
1887 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001888 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001889 return WL1271_ROLE_P2P_CL;
1890 else
1891 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001892
Eliad Peller227e81e2011-08-14 13:17:26 +03001893 case BSS_TYPE_IBSS:
1894 return WL1271_ROLE_IBSS;
1895
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001896 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001897 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001898 }
1899 return WL12XX_INVALID_ROLE_TYPE;
1900}
1901
Eliad Peller83587502011-10-10 10:12:53 +02001902static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001903{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001904 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001905 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001906
Eliad Peller48e93e42011-10-10 10:12:58 +02001907 /* clear everything but the persistent data */
1908 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001909
1910 switch (ieee80211_vif_type_p2p(vif)) {
1911 case NL80211_IFTYPE_P2P_CLIENT:
1912 wlvif->p2p = 1;
1913 /* fall-through */
1914 case NL80211_IFTYPE_STATION:
1915 wlvif->bss_type = BSS_TYPE_STA_BSS;
1916 break;
1917 case NL80211_IFTYPE_ADHOC:
1918 wlvif->bss_type = BSS_TYPE_IBSS;
1919 break;
1920 case NL80211_IFTYPE_P2P_GO:
1921 wlvif->p2p = 1;
1922 /* fall-through */
1923 case NL80211_IFTYPE_AP:
1924 wlvif->bss_type = BSS_TYPE_AP_BSS;
1925 break;
1926 default:
1927 wlvif->bss_type = MAX_BSS_TYPE;
1928 return -EOPNOTSUPP;
1929 }
1930
Eliad Peller0603d892011-10-05 11:55:51 +02001931 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001932 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001933 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001934
Eliad Pellere936bbe2011-10-05 11:55:56 +02001935 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1936 wlvif->bss_type == BSS_TYPE_IBSS) {
1937 /* init sta/ibss data */
1938 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001939 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1940 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1941 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001942 } else {
1943 /* init ap data */
1944 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1945 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001946 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1947 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1948 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1949 wl12xx_allocate_rate_policy(wl,
1950 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001951 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001952
Eliad Peller83587502011-10-10 10:12:53 +02001953 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1954 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001955 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001956 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001957 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001958 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1959
Eliad Peller1b92f152011-10-10 10:13:09 +02001960 /*
1961 * mac80211 configures some values globally, while we treat them
1962 * per-interface. thus, on init, we have to copy them from wl
1963 */
1964 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001965 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001966 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02001967
Eliad Peller9eb599e2011-10-10 10:12:59 +02001968 INIT_WORK(&wlvif->rx_streaming_enable_work,
1969 wl1271_rx_streaming_enable_work);
1970 INIT_WORK(&wlvif->rx_streaming_disable_work,
1971 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02001972 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02001973 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001974
Eliad Peller9eb599e2011-10-10 10:12:59 +02001975 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1976 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001977 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001978}
1979
Eliad Peller1d095472011-10-10 10:12:49 +02001980static bool wl12xx_init_fw(struct wl1271 *wl)
1981{
1982 int retries = WL1271_BOOT_RETRIES;
1983 bool booted = false;
1984 struct wiphy *wiphy = wl->hw->wiphy;
1985 int ret;
1986
1987 while (retries) {
1988 retries--;
1989 ret = wl1271_chip_wakeup(wl);
1990 if (ret < 0)
1991 goto power_off;
1992
1993 ret = wl1271_boot(wl);
1994 if (ret < 0)
1995 goto power_off;
1996
1997 ret = wl1271_hw_init(wl);
1998 if (ret < 0)
1999 goto irq_disable;
2000
2001 booted = true;
2002 break;
2003
2004irq_disable:
2005 mutex_unlock(&wl->mutex);
2006 /* Unlocking the mutex in the middle of handling is
2007 inherently unsafe. In this case we deem it safe to do,
2008 because we need to let any possibly pending IRQ out of
2009 the system (and while we are WL1271_STATE_OFF the IRQ
2010 work function will not do anything.) Also, any other
2011 possible concurrent operations will fail due to the
2012 current state, hence the wl1271 struct should be safe. */
2013 wl1271_disable_interrupts(wl);
2014 wl1271_flush_deferred_work(wl);
2015 cancel_work_sync(&wl->netstack_work);
2016 mutex_lock(&wl->mutex);
2017power_off:
2018 wl1271_power_off(wl);
2019 }
2020
2021 if (!booted) {
2022 wl1271_error("firmware boot failed despite %d retries",
2023 WL1271_BOOT_RETRIES);
2024 goto out;
2025 }
2026
2027 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2028
2029 /* update hw/fw version info in wiphy struct */
2030 wiphy->hw_version = wl->chip.id;
2031 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2032 sizeof(wiphy->fw_version));
2033
2034 /*
2035 * Now we know if 11a is supported (info from the NVS), so disable
2036 * 11a channels if not supported
2037 */
2038 if (!wl->enable_11a)
2039 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2040
2041 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2042 wl->enable_11a ? "" : "not ");
2043
2044 wl->state = WL1271_STATE_ON;
2045out:
2046 return booted;
2047}
2048
Eliad Peller92e712d2011-12-18 20:25:43 +02002049static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2050{
2051 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2052}
2053
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002054static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2055 struct ieee80211_vif *vif)
2056{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002057 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002058 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002059 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002060 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002061 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002062
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002063 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002064 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002065
2066 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002067 ret = wl1271_ps_elp_wakeup(wl);
2068 if (ret < 0)
2069 goto out_unlock;
2070
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002071 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002072 wl1271_debug(DEBUG_MAC80211,
2073 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002074 ret = -EBUSY;
2075 goto out;
2076 }
2077
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002078 /*
2079 * in some very corner case HW recovery scenarios its possible to
2080 * get here before __wl1271_op_remove_interface is complete, so
2081 * opt out if that is the case.
2082 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002083 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2084 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002085 ret = -EBUSY;
2086 goto out;
2087 }
2088
Eliad Peller83587502011-10-10 10:12:53 +02002089 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002090 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002091 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002092
Eliad Peller252efa42011-10-05 11:56:00 +02002093 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002094 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002095 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2096 ret = -EINVAL;
2097 goto out;
2098 }
Eliad Peller1d095472011-10-10 10:12:49 +02002099
Eliad Peller784f6942011-10-05 11:55:39 +02002100 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002101 * TODO: after the nvs issue will be solved, move this block
2102 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002103 */
Eliad Peller1d095472011-10-10 10:12:49 +02002104 if (wl->state == WL1271_STATE_OFF) {
2105 /*
2106 * we still need this in order to configure the fw
2107 * while uploading the nvs
2108 */
2109 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002110
Eliad Peller1d095472011-10-10 10:12:49 +02002111 booted = wl12xx_init_fw(wl);
2112 if (!booted) {
2113 ret = -EINVAL;
2114 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002115 }
Eliad Peller1d095472011-10-10 10:12:49 +02002116 }
Eliad Peller04e80792011-08-14 13:17:09 +03002117
Eliad Peller1d095472011-10-10 10:12:49 +02002118 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2119 wlvif->bss_type == BSS_TYPE_IBSS) {
2120 /*
2121 * The device role is a special role used for
2122 * rx and tx frames prior to association (as
2123 * the STA role can get packets only from
2124 * its associated bssid)
2125 */
Eliad Peller784f6942011-10-05 11:55:39 +02002126 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002127 WL1271_ROLE_DEVICE,
2128 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002129 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002130 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002131 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002132
Eliad Peller1d095472011-10-10 10:12:49 +02002133 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2134 role_type, &wlvif->role_id);
2135 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002136 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002137
2138 ret = wl1271_init_vif_specific(wl, vif);
2139 if (ret < 0)
2140 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002141
2142 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002143 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002144 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002145
2146 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2147 wl->ap_count++;
2148 else
2149 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002150out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002151 wl1271_ps_elp_sleep(wl);
2152out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002153 mutex_unlock(&wl->mutex);
2154
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002155 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002156 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002157 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002158 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002159
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002160 return ret;
2161}
2162
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002163static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002164 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002165 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002166{
Eliad Peller536129c2011-10-05 11:55:45 +02002167 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002168 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002169
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002170 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002171
Eliad Peller10c8cd02011-10-10 10:13:06 +02002172 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2173 return;
2174
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002175 wl->vif = NULL;
2176
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002177 /* because of hardware recovery, we may get here twice */
2178 if (wl->state != WL1271_STATE_ON)
2179 return;
2180
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002181 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002182
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002183 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002184 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002185 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002186
Eliad Pellerbaf62772011-10-10 10:12:52 +02002187 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2188 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002189 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002190 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002191 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002192 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002193 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002194 }
2195
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002196 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2197 /* disable active roles */
2198 ret = wl1271_ps_elp_wakeup(wl);
2199 if (ret < 0)
2200 goto deinit;
2201
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002202 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2203 wlvif->bss_type == BSS_TYPE_IBSS) {
2204 if (wl12xx_dev_role_started(wlvif))
2205 wl12xx_stop_dev(wl, wlvif);
2206
Eliad Peller7edebf52011-10-05 11:55:52 +02002207 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002208 if (ret < 0)
2209 goto deinit;
2210 }
2211
Eliad Peller0603d892011-10-05 11:55:51 +02002212 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002213 if (ret < 0)
2214 goto deinit;
2215
2216 wl1271_ps_elp_sleep(wl);
2217 }
2218deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002219 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002220 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002221
2222 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2223 wlvif->bss_type == BSS_TYPE_IBSS) {
2224 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2225 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2226 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2227 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2228 } else {
2229 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2230 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2231 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2232 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2233 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2234 wl12xx_free_rate_policy(wl,
2235 &wlvif->ap.ucast_rate_idx[i]);
2236 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002237
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002238 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002239 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002240 if (wl->last_wlvif == wlvif)
2241 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002242 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002243 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002244 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002245 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002246
Eliad Pellera4e41302011-10-11 11:49:15 +02002247 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2248 wl->ap_count--;
2249 else
2250 wl->sta_count--;
2251
Eliad Pellerbaf62772011-10-10 10:12:52 +02002252 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002253 del_timer_sync(&wlvif->rx_streaming_timer);
2254 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2255 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002256 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002257
Eliad Pellerbaf62772011-10-10 10:12:52 +02002258 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002259}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002260
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002261static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2262 struct ieee80211_vif *vif)
2263{
2264 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002265 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002266 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002267
2268 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002269
2270 if (wl->state == WL1271_STATE_OFF ||
2271 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2272 goto out;
2273
Juuso Oikarinen67353292010-11-18 15:19:02 +02002274 /*
2275 * wl->vif can be null here if someone shuts down the interface
2276 * just when hardware recovery has been started.
2277 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002278 wl12xx_for_each_wlvif(wl, iter) {
2279 if (iter != wlvif)
2280 continue;
2281
Eliad Peller536129c2011-10-05 11:55:45 +02002282 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002283 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002284 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002285 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002286out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002287 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002288 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002289}
2290
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002291static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2292 struct ieee80211_vif *vif,
2293 enum nl80211_iftype new_type, bool p2p)
2294{
2295 wl1271_op_remove_interface(hw, vif);
2296
2297 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2298 vif->p2p = p2p;
2299 return wl1271_op_add_interface(hw, vif);
2300}
2301
Eliad Peller87fbcb02011-10-05 11:55:41 +02002302static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2303 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002304{
2305 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002306 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002307
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002308 /*
2309 * One of the side effects of the JOIN command is that is clears
2310 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2311 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002312 * Currently the only valid scenario for JOIN during association
2313 * is on roaming, in which case we will also be given new keys.
2314 * Keep the below message for now, unless it starts bothering
2315 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002316 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002317 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002318 wl1271_info("JOIN while associated.");
2319
2320 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002321 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002322
Eliad Peller227e81e2011-08-14 13:17:26 +03002323 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002324 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002325 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002326 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002327 if (ret < 0)
2328 goto out;
2329
Eliad Pellerba8447f2011-10-10 10:13:00 +02002330 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002331 goto out;
2332
2333 /*
2334 * The join command disable the keep-alive mode, shut down its process,
2335 * and also clear the template config, so we need to reset it all after
2336 * the join. The acx_aid starts the keep-alive process, and the order
2337 * of the commands below is relevant.
2338 */
Eliad Peller0603d892011-10-05 11:55:51 +02002339 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002340 if (ret < 0)
2341 goto out;
2342
Eliad Peller0603d892011-10-05 11:55:51 +02002343 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002344 if (ret < 0)
2345 goto out;
2346
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002347 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002348 if (ret < 0)
2349 goto out;
2350
Eliad Peller0603d892011-10-05 11:55:51 +02002351 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2352 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002353 ACX_KEEP_ALIVE_TPL_VALID);
2354 if (ret < 0)
2355 goto out;
2356
2357out:
2358 return ret;
2359}
2360
Eliad Peller0603d892011-10-05 11:55:51 +02002361static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002362{
2363 int ret;
2364
Eliad Peller52630c52011-10-10 10:13:08 +02002365 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002366 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2367
Shahar Levi6d158ff2011-09-08 13:01:33 +03002368 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002369 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002370 }
2371
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002372 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002373 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002374 if (ret < 0)
2375 goto out;
2376
Oz Krakowskib992c682011-06-26 10:36:02 +03002377 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002378 wlvif->tx_security_last_seq_lsb = 0;
2379 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002380
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002381out:
2382 return ret;
2383}
2384
Eliad Peller87fbcb02011-10-05 11:55:41 +02002385static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002386{
Eliad Peller1b92f152011-10-10 10:13:09 +02002387 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002388 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002389}
2390
Eliad Peller87fbcb02011-10-05 11:55:41 +02002391static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2392 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002393{
2394 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002395 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2396
2397 if (idle == cur_idle)
2398 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002399
2400 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002401 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002402 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002403 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002404 if (ret < 0)
2405 goto out;
2406 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002407 wlvif->rate_set =
2408 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2409 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002410 if (ret < 0)
2411 goto out;
2412 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002413 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002414 ACX_KEEP_ALIVE_TPL_INVALID);
2415 if (ret < 0)
2416 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002417 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002418 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002419 /* The current firmware only supports sched_scan in idle */
2420 if (wl->sched_scanning) {
2421 wl1271_scan_sched_scan_stop(wl);
2422 ieee80211_sched_scan_stopped(wl->hw);
2423 }
2424
Eliad Peller679a6732011-10-11 11:55:44 +02002425 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002426 if (ret < 0)
2427 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002428 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002429 }
2430
2431out:
2432 return ret;
2433}
2434
Eliad Peller9f259c42011-10-10 10:13:12 +02002435static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2436 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002437{
Eliad Peller9f259c42011-10-10 10:13:12 +02002438 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2439 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002440
2441 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2442
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002443 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002444 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002445 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002446 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002447 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002448 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002449 wlvif->band = conf->channel->band;
2450 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002451
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002452 if (!is_ap) {
2453 /*
2454 * FIXME: the mac80211 should really provide a fixed
2455 * rate to use here. for now, just use the smallest
2456 * possible rate for the band as a fixed rate for
2457 * association frames and other control messages.
2458 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002459 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002460 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002461
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002462 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002463 wl1271_tx_min_rate_get(wl,
2464 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002465 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002466 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002467 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002468 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002469
Eliad Pellerba8447f2011-10-10 10:13:00 +02002470 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2471 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002472 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002473 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002474 ret = wl12xx_croc(wl,
2475 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002476 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002477 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002478 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002479 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002480 if (ret < 0)
2481 wl1271_warning("cmd join on channel "
2482 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002483 } else {
2484 /*
2485 * change the ROC channel. do it only if we are
2486 * not idle. otherwise, CROC will be called
2487 * anyway.
2488 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002489 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002490 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002491 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002492 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002493 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002494
Eliad Peller679a6732011-10-11 11:55:44 +02002495 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002496 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002497 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002498 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002499 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002500 }
2501 }
2502
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002503 /*
2504 * if mac80211 changes the PSM mode, make sure the mode is not
2505 * incorrectly changed after the pspoll failure active window.
2506 */
2507 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002508 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002509
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002510 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002511 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2512 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002513
2514 /*
2515 * We enter PSM only if we're already associated.
2516 * If we're not, we'll enter it when joining an SSID,
2517 * through the bss_info_changed() hook.
2518 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002519 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002520 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002521 ret = wl1271_ps_set_mode(wl, wlvif,
2522 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002523 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002524 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002525 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002526 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002527 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002528
Eliad Pellerc29bb002011-10-10 10:13:03 +02002529 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002530
Eliad Pellerc29bb002011-10-10 10:13:03 +02002531 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002532 ret = wl1271_ps_set_mode(wl, wlvif,
2533 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002534 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002535 }
2536
Eliad Peller6bd65022011-10-10 10:13:11 +02002537 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002538 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002539 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002540 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002541
Eliad Peller6bd65022011-10-10 10:13:11 +02002542 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002543 }
2544
Eliad Peller9f259c42011-10-10 10:13:12 +02002545 return 0;
2546}
2547
2548static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2549{
2550 struct wl1271 *wl = hw->priv;
2551 struct wl12xx_vif *wlvif;
2552 struct ieee80211_conf *conf = &hw->conf;
2553 int channel, ret = 0;
2554
2555 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2556
2557 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2558 " changed 0x%x",
2559 channel,
2560 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2561 conf->power_level,
2562 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2563 changed);
2564
2565 /*
2566 * mac80211 will go to idle nearly immediately after transmitting some
2567 * frames, such as the deauth. To make sure those frames reach the air,
2568 * wait here until the TX queue is fully flushed.
2569 */
2570 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2571 (conf->flags & IEEE80211_CONF_IDLE))
2572 wl1271_tx_flush(wl);
2573
2574 mutex_lock(&wl->mutex);
2575
2576 /* we support configuring the channel and band even while off */
2577 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2578 wl->band = conf->channel->band;
2579 wl->channel = channel;
2580 }
2581
2582 if (changed & IEEE80211_CONF_CHANGE_POWER)
2583 wl->power_level = conf->power_level;
2584
2585 if (unlikely(wl->state == WL1271_STATE_OFF))
2586 goto out;
2587
2588 ret = wl1271_ps_elp_wakeup(wl);
2589 if (ret < 0)
2590 goto out;
2591
2592 /* configure each interface */
2593 wl12xx_for_each_wlvif(wl, wlvif) {
2594 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2595 if (ret < 0)
2596 goto out_sleep;
2597 }
2598
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002599out_sleep:
2600 wl1271_ps_elp_sleep(wl);
2601
2602out:
2603 mutex_unlock(&wl->mutex);
2604
2605 return ret;
2606}
2607
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002608struct wl1271_filter_params {
2609 bool enabled;
2610 int mc_list_length;
2611 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2612};
2613
Jiri Pirko22bedad2010-04-01 21:22:57 +00002614static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2615 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002616{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002617 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002618 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002619 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002620
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002621 if (unlikely(wl->state == WL1271_STATE_OFF))
2622 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002623
Juuso Oikarinen74441132009-10-13 12:47:53 +03002624 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002625 if (!fp) {
2626 wl1271_error("Out of memory setting filters.");
2627 return 0;
2628 }
2629
2630 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002631 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002632 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2633 fp->enabled = false;
2634 } else {
2635 fp->enabled = true;
2636 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002637 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002638 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002639 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002640 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002641 }
2642
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002643 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002644}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002645
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002646#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2647 FIF_ALLMULTI | \
2648 FIF_FCSFAIL | \
2649 FIF_BCN_PRBRESP_PROMISC | \
2650 FIF_CONTROL | \
2651 FIF_OTHER_BSS)
2652
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002653static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2654 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002655 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002656{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002657 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002658 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002659 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002660
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002661 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002662
Arik Nemtsov7d057862010-10-16 19:25:35 +02002663 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2664 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002665
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002666 mutex_lock(&wl->mutex);
2667
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002668 *total &= WL1271_SUPPORTED_FILTERS;
2669 changed &= WL1271_SUPPORTED_FILTERS;
2670
2671 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002672 goto out;
2673
Ido Yariva6208652011-03-01 15:14:41 +02002674 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002675 if (ret < 0)
2676 goto out;
2677
Eliad Peller6e8cd332011-10-10 10:13:13 +02002678 wl12xx_for_each_wlvif(wl, wlvif) {
2679 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2680 if (*total & FIF_ALLMULTI)
2681 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2682 false,
2683 NULL, 0);
2684 else if (fp)
2685 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2686 fp->enabled,
2687 fp->mc_list,
2688 fp->mc_list_length);
2689 if (ret < 0)
2690 goto out_sleep;
2691 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002692 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002693
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002694 /*
2695 * the fw doesn't provide an api to configure the filters. instead,
2696 * the filters configuration is based on the active roles / ROC
2697 * state.
2698 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002699
2700out_sleep:
2701 wl1271_ps_elp_sleep(wl);
2702
2703out:
2704 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002705 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002706}
2707
Eliad Peller170d0e62011-10-05 11:56:06 +02002708static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2709 u8 id, u8 key_type, u8 key_size,
2710 const u8 *key, u8 hlid, u32 tx_seq_32,
2711 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002712{
2713 struct wl1271_ap_key *ap_key;
2714 int i;
2715
2716 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2717
2718 if (key_size > MAX_KEY_SIZE)
2719 return -EINVAL;
2720
2721 /*
2722 * Find next free entry in ap_keys. Also check we are not replacing
2723 * an existing key.
2724 */
2725 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002726 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002727 break;
2728
Eliad Peller170d0e62011-10-05 11:56:06 +02002729 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002730 wl1271_warning("trying to record key replacement");
2731 return -EINVAL;
2732 }
2733 }
2734
2735 if (i == MAX_NUM_KEYS)
2736 return -EBUSY;
2737
2738 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2739 if (!ap_key)
2740 return -ENOMEM;
2741
2742 ap_key->id = id;
2743 ap_key->key_type = key_type;
2744 ap_key->key_size = key_size;
2745 memcpy(ap_key->key, key, key_size);
2746 ap_key->hlid = hlid;
2747 ap_key->tx_seq_32 = tx_seq_32;
2748 ap_key->tx_seq_16 = tx_seq_16;
2749
Eliad Peller170d0e62011-10-05 11:56:06 +02002750 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002751 return 0;
2752}
2753
Eliad Peller170d0e62011-10-05 11:56:06 +02002754static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002755{
2756 int i;
2757
2758 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002759 kfree(wlvif->ap.recorded_keys[i]);
2760 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002761 }
2762}
2763
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002764static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002765{
2766 int i, ret = 0;
2767 struct wl1271_ap_key *key;
2768 bool wep_key_added = false;
2769
2770 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002771 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002772 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002773 break;
2774
Eliad Peller170d0e62011-10-05 11:56:06 +02002775 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002776 hlid = key->hlid;
2777 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002778 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002779
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002780 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002781 key->id, key->key_type,
2782 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002783 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002784 key->tx_seq_16);
2785 if (ret < 0)
2786 goto out;
2787
2788 if (key->key_type == KEY_WEP)
2789 wep_key_added = true;
2790 }
2791
2792 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002793 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002794 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002795 if (ret < 0)
2796 goto out;
2797 }
2798
2799out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002800 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002801 return ret;
2802}
2803
Eliad Peller536129c2011-10-05 11:55:45 +02002804static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2805 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002806 u8 key_size, const u8 *key, u32 tx_seq_32,
2807 u16 tx_seq_16, struct ieee80211_sta *sta)
2808{
2809 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002810 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002811
2812 if (is_ap) {
2813 struct wl1271_station *wl_sta;
2814 u8 hlid;
2815
2816 if (sta) {
2817 wl_sta = (struct wl1271_station *)sta->drv_priv;
2818 hlid = wl_sta->hlid;
2819 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002820 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002821 }
2822
Eliad Peller53d40d02011-10-10 10:13:02 +02002823 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002824 /*
2825 * We do not support removing keys after AP shutdown.
2826 * Pretend we do to make mac80211 happy.
2827 */
2828 if (action != KEY_ADD_OR_REPLACE)
2829 return 0;
2830
Eliad Peller170d0e62011-10-05 11:56:06 +02002831 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002832 key_type, key_size,
2833 key, hlid, tx_seq_32,
2834 tx_seq_16);
2835 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002836 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002837 id, key_type, key_size,
2838 key, hlid, tx_seq_32,
2839 tx_seq_16);
2840 }
2841
2842 if (ret < 0)
2843 return ret;
2844 } else {
2845 const u8 *addr;
2846 static const u8 bcast_addr[ETH_ALEN] = {
2847 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2848 };
2849
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002850 /*
2851 * A STA set to GEM cipher requires 2 tx spare blocks.
2852 * Return to default value when GEM cipher key is removed
2853 */
2854 if (key_type == KEY_GEM) {
2855 if (action == KEY_ADD_OR_REPLACE)
2856 wl->tx_spare_blocks = 2;
2857 else if (action == KEY_REMOVE)
2858 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2859 }
2860
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002861 addr = sta ? sta->addr : bcast_addr;
2862
2863 if (is_zero_ether_addr(addr)) {
2864 /* We dont support TX only encryption */
2865 return -EOPNOTSUPP;
2866 }
2867
2868 /* The wl1271 does not allow to remove unicast keys - they
2869 will be cleared automatically on next CMD_JOIN. Ignore the
2870 request silently, as we dont want the mac80211 to emit
2871 an error message. */
2872 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2873 return 0;
2874
Eliad Peller010d3d32011-08-14 13:17:31 +03002875 /* don't remove key if hlid was already deleted */
2876 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002877 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002878 return 0;
2879
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002880 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002881 id, key_type, key_size,
2882 key, addr, tx_seq_32,
2883 tx_seq_16);
2884 if (ret < 0)
2885 return ret;
2886
2887 /* the default WEP key needs to be configured at least once */
2888 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002889 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002890 wlvif->default_key,
2891 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002892 if (ret < 0)
2893 return ret;
2894 }
2895 }
2896
2897 return 0;
2898}
2899
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002900static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2901 struct ieee80211_vif *vif,
2902 struct ieee80211_sta *sta,
2903 struct ieee80211_key_conf *key_conf)
2904{
2905 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002906 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002907 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002908 u32 tx_seq_32 = 0;
2909 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002910 u8 key_type;
2911
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002912 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2913
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002914 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002915 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002916 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002917 key_conf->keylen, key_conf->flags);
2918 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2919
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002920 mutex_lock(&wl->mutex);
2921
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002922 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2923 ret = -EAGAIN;
2924 goto out_unlock;
2925 }
2926
Ido Yariva6208652011-03-01 15:14:41 +02002927 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002928 if (ret < 0)
2929 goto out_unlock;
2930
Johannes Berg97359d12010-08-10 09:46:38 +02002931 switch (key_conf->cipher) {
2932 case WLAN_CIPHER_SUITE_WEP40:
2933 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002934 key_type = KEY_WEP;
2935
2936 key_conf->hw_key_idx = key_conf->keyidx;
2937 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002938 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002939 key_type = KEY_TKIP;
2940
2941 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002942 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2943 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002944 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002945 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002946 key_type = KEY_AES;
2947
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002948 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002949 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2950 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002951 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002952 case WL1271_CIPHER_SUITE_GEM:
2953 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002954 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2955 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002956 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002957 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002958 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002959
2960 ret = -EOPNOTSUPP;
2961 goto out_sleep;
2962 }
2963
2964 switch (cmd) {
2965 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002966 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002967 key_conf->keyidx, key_type,
2968 key_conf->keylen, key_conf->key,
2969 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002970 if (ret < 0) {
2971 wl1271_error("Could not add or replace key");
2972 goto out_sleep;
2973 }
2974 break;
2975
2976 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002977 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002978 key_conf->keyidx, key_type,
2979 key_conf->keylen, key_conf->key,
2980 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002981 if (ret < 0) {
2982 wl1271_error("Could not remove key");
2983 goto out_sleep;
2984 }
2985 break;
2986
2987 default:
2988 wl1271_error("Unsupported key cmd 0x%x", cmd);
2989 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002990 break;
2991 }
2992
2993out_sleep:
2994 wl1271_ps_elp_sleep(wl);
2995
2996out_unlock:
2997 mutex_unlock(&wl->mutex);
2998
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002999 return ret;
3000}
3001
3002static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003003 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003004 struct cfg80211_scan_request *req)
3005{
3006 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003007 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3008
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003009 int ret;
3010 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003011 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003012
3013 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3014
3015 if (req->n_ssids) {
3016 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003017 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003018 }
3019
3020 mutex_lock(&wl->mutex);
3021
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003022 if (wl->state == WL1271_STATE_OFF) {
3023 /*
3024 * We cannot return -EBUSY here because cfg80211 will expect
3025 * a call to ieee80211_scan_completed if we do - in this case
3026 * there won't be any call.
3027 */
3028 ret = -EAGAIN;
3029 goto out;
3030 }
3031
Ido Yariva6208652011-03-01 15:14:41 +02003032 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003033 if (ret < 0)
3034 goto out;
3035
Eliad Peller92e712d2011-12-18 20:25:43 +02003036 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
3037 test_bit(wlvif->role_id, wl->roc_map)) {
3038 /* don't allow scanning right now */
3039 ret = -EBUSY;
3040 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003041 }
3042
Eliad Peller92e712d2011-12-18 20:25:43 +02003043 /* cancel ROC before scanning */
3044 if (wl12xx_dev_role_started(wlvif))
3045 wl12xx_stop_dev(wl, wlvif);
3046
Eliad Peller784f6942011-10-05 11:55:39 +02003047 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003048out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003049 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003050out:
3051 mutex_unlock(&wl->mutex);
3052
3053 return ret;
3054}
3055
Eliad Peller73ecce32011-06-27 13:06:45 +03003056static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3057 struct ieee80211_vif *vif)
3058{
3059 struct wl1271 *wl = hw->priv;
3060 int ret;
3061
3062 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3063
3064 mutex_lock(&wl->mutex);
3065
3066 if (wl->state == WL1271_STATE_OFF)
3067 goto out;
3068
3069 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3070 goto out;
3071
3072 ret = wl1271_ps_elp_wakeup(wl);
3073 if (ret < 0)
3074 goto out;
3075
3076 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3077 ret = wl1271_scan_stop(wl);
3078 if (ret < 0)
3079 goto out_sleep;
3080 }
3081 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3082 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003083 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003084 wl->scan.req = NULL;
3085 ieee80211_scan_completed(wl->hw, true);
3086
3087out_sleep:
3088 wl1271_ps_elp_sleep(wl);
3089out:
3090 mutex_unlock(&wl->mutex);
3091
3092 cancel_delayed_work_sync(&wl->scan_complete_work);
3093}
3094
Luciano Coelho33c2c062011-05-10 14:46:02 +03003095static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3096 struct ieee80211_vif *vif,
3097 struct cfg80211_sched_scan_request *req,
3098 struct ieee80211_sched_scan_ies *ies)
3099{
3100 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003101 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003102 int ret;
3103
3104 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3105
3106 mutex_lock(&wl->mutex);
3107
3108 ret = wl1271_ps_elp_wakeup(wl);
3109 if (ret < 0)
3110 goto out;
3111
Eliad Peller536129c2011-10-05 11:55:45 +02003112 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003113 if (ret < 0)
3114 goto out_sleep;
3115
Eliad Peller536129c2011-10-05 11:55:45 +02003116 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003117 if (ret < 0)
3118 goto out_sleep;
3119
3120 wl->sched_scanning = true;
3121
3122out_sleep:
3123 wl1271_ps_elp_sleep(wl);
3124out:
3125 mutex_unlock(&wl->mutex);
3126 return ret;
3127}
3128
3129static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3130 struct ieee80211_vif *vif)
3131{
3132 struct wl1271 *wl = hw->priv;
3133 int ret;
3134
3135 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3136
3137 mutex_lock(&wl->mutex);
3138
3139 ret = wl1271_ps_elp_wakeup(wl);
3140 if (ret < 0)
3141 goto out;
3142
3143 wl1271_scan_sched_scan_stop(wl);
3144
3145 wl1271_ps_elp_sleep(wl);
3146out:
3147 mutex_unlock(&wl->mutex);
3148}
3149
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003150static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3151{
3152 struct wl1271 *wl = hw->priv;
3153 int ret = 0;
3154
3155 mutex_lock(&wl->mutex);
3156
3157 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3158 ret = -EAGAIN;
3159 goto out;
3160 }
3161
Ido Yariva6208652011-03-01 15:14:41 +02003162 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003163 if (ret < 0)
3164 goto out;
3165
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003166 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003167 if (ret < 0)
3168 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3169
3170 wl1271_ps_elp_sleep(wl);
3171
3172out:
3173 mutex_unlock(&wl->mutex);
3174
3175 return ret;
3176}
3177
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003178static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3179{
3180 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003181 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003182 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003183
3184 mutex_lock(&wl->mutex);
3185
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003186 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3187 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003188 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003189 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003190
Ido Yariva6208652011-03-01 15:14:41 +02003191 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003192 if (ret < 0)
3193 goto out;
3194
Eliad Peller6e8cd332011-10-10 10:13:13 +02003195 wl12xx_for_each_wlvif(wl, wlvif) {
3196 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3197 if (ret < 0)
3198 wl1271_warning("set rts threshold failed: %d", ret);
3199 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003200 wl1271_ps_elp_sleep(wl);
3201
3202out:
3203 mutex_unlock(&wl->mutex);
3204
3205 return ret;
3206}
3207
Eliad Peller1fe9f162011-10-05 11:55:48 +02003208static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003209 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003210{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003211 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003212 u8 ssid_len;
3213 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3214 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003215
Eliad Peller889cb362011-05-01 09:56:45 +03003216 if (!ptr) {
3217 wl1271_error("No SSID in IEs!");
3218 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003219 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003220
Eliad Peller889cb362011-05-01 09:56:45 +03003221 ssid_len = ptr[1];
3222 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3223 wl1271_error("SSID is too long!");
3224 return -EINVAL;
3225 }
3226
Eliad Peller1fe9f162011-10-05 11:55:48 +02003227 wlvif->ssid_len = ssid_len;
3228 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003229 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003230}
3231
Eliad Pellerd48055d2011-09-15 12:07:04 +03003232static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3233{
3234 int len;
3235 const u8 *next, *end = skb->data + skb->len;
3236 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3237 skb->len - ieoffset);
3238 if (!ie)
3239 return;
3240 len = ie[1] + 2;
3241 next = ie + len;
3242 memmove(ie, next, end - next);
3243 skb_trim(skb, skb->len - len);
3244}
3245
Eliad Peller26b4bf22011-09-15 12:07:05 +03003246static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3247 unsigned int oui, u8 oui_type,
3248 int ieoffset)
3249{
3250 int len;
3251 const u8 *next, *end = skb->data + skb->len;
3252 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3253 skb->data + ieoffset,
3254 skb->len - ieoffset);
3255 if (!ie)
3256 return;
3257 len = ie[1] + 2;
3258 next = ie + len;
3259 memmove(ie, next, end - next);
3260 skb_trim(skb, skb->len - len);
3261}
3262
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003263static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3264 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003265{
3266 struct sk_buff *skb;
3267 int ret;
3268
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003269 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003270 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003271 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003272
3273 ret = wl1271_cmd_template_set(wl,
3274 CMD_TEMPL_AP_PROBE_RESPONSE,
3275 skb->data,
3276 skb->len, 0,
3277 rates);
3278
3279 dev_kfree_skb(skb);
3280 return ret;
3281}
3282
3283static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3284 struct ieee80211_vif *vif,
3285 u8 *probe_rsp_data,
3286 size_t probe_rsp_len,
3287 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003288{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003289 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3290 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003291 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3292 int ssid_ie_offset, ie_offset, templ_len;
3293 const u8 *ptr;
3294
3295 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003296 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003297 return wl1271_cmd_template_set(wl,
3298 CMD_TEMPL_AP_PROBE_RESPONSE,
3299 probe_rsp_data,
3300 probe_rsp_len, 0,
3301 rates);
3302
3303 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3304 wl1271_error("probe_rsp template too big");
3305 return -EINVAL;
3306 }
3307
3308 /* start searching from IE offset */
3309 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3310
3311 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3312 probe_rsp_len - ie_offset);
3313 if (!ptr) {
3314 wl1271_error("No SSID in beacon!");
3315 return -EINVAL;
3316 }
3317
3318 ssid_ie_offset = ptr - probe_rsp_data;
3319 ptr += (ptr[1] + 2);
3320
3321 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3322
3323 /* insert SSID from bss_conf */
3324 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3325 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3326 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3327 bss_conf->ssid, bss_conf->ssid_len);
3328 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3329
3330 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3331 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3332 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3333
3334 return wl1271_cmd_template_set(wl,
3335 CMD_TEMPL_AP_PROBE_RESPONSE,
3336 probe_rsp_templ,
3337 templ_len, 0,
3338 rates);
3339}
3340
Arik Nemtsove78a2872010-10-16 19:07:21 +02003341static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003342 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003343 struct ieee80211_bss_conf *bss_conf,
3344 u32 changed)
3345{
Eliad Peller0603d892011-10-05 11:55:51 +02003346 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003347 int ret = 0;
3348
3349 if (changed & BSS_CHANGED_ERP_SLOT) {
3350 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003351 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003352 else
Eliad Peller0603d892011-10-05 11:55:51 +02003353 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003354 if (ret < 0) {
3355 wl1271_warning("Set slot time failed %d", ret);
3356 goto out;
3357 }
3358 }
3359
3360 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3361 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003362 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003363 else
Eliad Peller0603d892011-10-05 11:55:51 +02003364 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003365 }
3366
3367 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3368 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003369 ret = wl1271_acx_cts_protect(wl, wlvif,
3370 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003371 else
Eliad Peller0603d892011-10-05 11:55:51 +02003372 ret = wl1271_acx_cts_protect(wl, wlvif,
3373 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003374 if (ret < 0) {
3375 wl1271_warning("Set ctsprotect failed %d", ret);
3376 goto out;
3377 }
3378 }
3379
3380out:
3381 return ret;
3382}
3383
3384static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3385 struct ieee80211_vif *vif,
3386 struct ieee80211_bss_conf *bss_conf,
3387 u32 changed)
3388{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003389 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003390 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003391 int ret = 0;
3392
3393 if ((changed & BSS_CHANGED_BEACON_INT)) {
3394 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3395 bss_conf->beacon_int);
3396
Eliad Peller6a899792011-10-05 11:55:58 +02003397 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003398 }
3399
Arik Nemtsov560f0022011-11-08 18:46:54 +02003400 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3401 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003402 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3403 wl1271_debug(DEBUG_AP, "probe response updated");
3404 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3405 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003406 }
3407
Arik Nemtsove78a2872010-10-16 19:07:21 +02003408 if ((changed & BSS_CHANGED_BEACON)) {
3409 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003410 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003411 int ieoffset = offsetof(struct ieee80211_mgmt,
3412 u.beacon.variable);
3413 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3414 u16 tmpl_id;
3415
Arik Nemtsov560f0022011-11-08 18:46:54 +02003416 if (!beacon) {
3417 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003418 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003419 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003420
3421 wl1271_debug(DEBUG_MASTER, "beacon updated");
3422
Eliad Peller1fe9f162011-10-05 11:55:48 +02003423 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003424 if (ret < 0) {
3425 dev_kfree_skb(beacon);
3426 goto out;
3427 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003428 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003429 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3430 CMD_TEMPL_BEACON;
3431 ret = wl1271_cmd_template_set(wl, tmpl_id,
3432 beacon->data,
3433 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003434 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003435 if (ret < 0) {
3436 dev_kfree_skb(beacon);
3437 goto out;
3438 }
3439
Arik Nemtsov560f0022011-11-08 18:46:54 +02003440 /*
3441 * In case we already have a probe-resp beacon set explicitly
3442 * by usermode, don't use the beacon data.
3443 */
3444 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3445 goto end_bcn;
3446
Eliad Pellerd48055d2011-09-15 12:07:04 +03003447 /* remove TIM ie from probe response */
3448 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3449
Eliad Peller26b4bf22011-09-15 12:07:05 +03003450 /*
3451 * remove p2p ie from probe response.
3452 * the fw reponds to probe requests that don't include
3453 * the p2p ie. probe requests with p2p ie will be passed,
3454 * and will be responded by the supplicant (the spec
3455 * forbids including the p2p ie when responding to probe
3456 * requests that didn't include it).
3457 */
3458 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3459 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3460
Arik Nemtsove78a2872010-10-16 19:07:21 +02003461 hdr = (struct ieee80211_hdr *) beacon->data;
3462 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3463 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003464 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003465 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003466 beacon->data,
3467 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003468 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003469 else
3470 ret = wl1271_cmd_template_set(wl,
3471 CMD_TEMPL_PROBE_RESPONSE,
3472 beacon->data,
3473 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003474 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003475end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003476 dev_kfree_skb(beacon);
3477 if (ret < 0)
3478 goto out;
3479 }
3480
3481out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003482 if (ret != 0)
3483 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003484 return ret;
3485}
3486
3487/* AP mode changes */
3488static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003489 struct ieee80211_vif *vif,
3490 struct ieee80211_bss_conf *bss_conf,
3491 u32 changed)
3492{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003493 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003494 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003495
Arik Nemtsove78a2872010-10-16 19:07:21 +02003496 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3497 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003498
Eliad Peller87fbcb02011-10-05 11:55:41 +02003499 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003500 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003501 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003502 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003503
Eliad Peller87fbcb02011-10-05 11:55:41 +02003504 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003505 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003506 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003507 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003508 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003509
Eliad Peller784f6942011-10-05 11:55:39 +02003510 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003511 if (ret < 0)
3512 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003513 }
3514
Arik Nemtsove78a2872010-10-16 19:07:21 +02003515 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3516 if (ret < 0)
3517 goto out;
3518
3519 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3520 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003521 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003522 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003523 if (ret < 0)
3524 goto out;
3525
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003526 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003527 if (ret < 0)
3528 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003529
Eliad Peller53d40d02011-10-10 10:13:02 +02003530 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003531 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003532 }
3533 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003534 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003535 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003536 if (ret < 0)
3537 goto out;
3538
Eliad Peller53d40d02011-10-10 10:13:02 +02003539 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003540 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3541 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003542 wl1271_debug(DEBUG_AP, "stopped AP");
3543 }
3544 }
3545 }
3546
Eliad Peller0603d892011-10-05 11:55:51 +02003547 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003548 if (ret < 0)
3549 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003550
3551 /* Handle HT information change */
3552 if ((changed & BSS_CHANGED_HT) &&
3553 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003554 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003555 bss_conf->ht_operation_mode);
3556 if (ret < 0) {
3557 wl1271_warning("Set ht information failed %d", ret);
3558 goto out;
3559 }
3560 }
3561
Arik Nemtsove78a2872010-10-16 19:07:21 +02003562out:
3563 return;
3564}
3565
3566/* STA/IBSS mode changes */
3567static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3568 struct ieee80211_vif *vif,
3569 struct ieee80211_bss_conf *bss_conf,
3570 u32 changed)
3571{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003572 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003573 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003574 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003575 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003576 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003577 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003578 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003579 bool sta_exists = false;
3580 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003581
3582 if (is_ibss) {
3583 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3584 changed);
3585 if (ret < 0)
3586 goto out;
3587 }
3588
Eliad Peller227e81e2011-08-14 13:17:26 +03003589 if (changed & BSS_CHANGED_IBSS) {
3590 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003591 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003592 ibss_joined = true;
3593 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003594 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3595 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003596 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003597 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003598 }
3599 }
3600 }
3601
3602 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003603 do_join = true;
3604
3605 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003606 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003607 do_join = true;
3608
Eliad Peller227e81e2011-08-14 13:17:26 +03003609 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003610 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3611 bss_conf->enable_beacon ? "enabled" : "disabled");
3612
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003613 do_join = true;
3614 }
3615
Eliad Pellerc31e4942011-10-23 08:21:55 +02003616 if (changed & BSS_CHANGED_IDLE) {
3617 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3618 if (ret < 0)
3619 wl1271_warning("idle mode change failed %d", ret);
3620 }
3621
Arik Nemtsove78a2872010-10-16 19:07:21 +02003622 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003623 bool enable = false;
3624 if (bss_conf->cqm_rssi_thold)
3625 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003626 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003627 bss_conf->cqm_rssi_thold,
3628 bss_conf->cqm_rssi_hyst);
3629 if (ret < 0)
3630 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003631 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003632 }
3633
Eliad Pellercdf09492011-10-05 11:55:44 +02003634 if (changed & BSS_CHANGED_BSSID)
3635 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003636 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003637 if (ret < 0)
3638 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003639
Eliad Peller784f6942011-10-05 11:55:39 +02003640 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003641 if (ret < 0)
3642 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003643
Eliad Pellerfa287b82010-12-26 09:27:50 +01003644 /* Need to update the BSSID (for filtering etc) */
3645 do_join = true;
3646 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003647
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003648 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3649 rcu_read_lock();
3650 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3651 if (!sta)
3652 goto sta_not_found;
3653
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003654 /* save the supp_rates of the ap */
3655 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3656 if (sta->ht_cap.ht_supported)
3657 sta_rate_set |=
3658 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003659 sta_ht_cap = sta->ht_cap;
3660 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003661
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003662sta_not_found:
3663 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003664 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003665
Arik Nemtsove78a2872010-10-16 19:07:21 +02003666 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003667 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003668 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003669 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003670 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003671 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003672
Eliad Peller74ec8392011-10-05 11:56:02 +02003673 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003674
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003675 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003676 * use basic rates from AP, and determine lowest rate
3677 * to use with control frames.
3678 */
3679 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003680 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003681 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003682 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003683 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003684 wl1271_tx_min_rate_get(wl,
3685 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003686 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003687 wlvif->rate_set =
3688 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003689 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003690 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003691 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003692 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003693 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003694
3695 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003696 * with wl1271, we don't need to update the
3697 * beacon_int and dtim_period, because the firmware
3698 * updates it by itself when the first beacon is
3699 * received after a join.
3700 */
Eliad Peller6840e372011-10-05 11:55:50 +02003701 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003702 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003703 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003704
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003705 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003706 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003707 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003708 dev_kfree_skb(wlvif->probereq);
3709 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003710 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003711 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003712 ieoffset = offsetof(struct ieee80211_mgmt,
3713 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003714 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003715
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003716 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003717 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003718 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003719 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003720 } else {
3721 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003722 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003723 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3724 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003725 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003726 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3727 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003728 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003729
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003730 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003731 dev_kfree_skb(wlvif->probereq);
3732 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003733
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003734 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003735 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003736
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003737 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003738 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003739 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003740 wl1271_tx_min_rate_get(wl,
3741 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003742 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003743 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003744 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003745
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003746 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003747 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003748
3749 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003750 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003751 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003752 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003753
3754 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003755 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003756 u32 conf_flags = wl->hw->conf.flags;
3757 /*
3758 * we might have to disable roc, if there was
3759 * no IF_OPER_UP notification.
3760 */
3761 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003762 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003763 if (ret < 0)
3764 goto out;
3765 }
3766 /*
3767 * (we also need to disable roc in case of
3768 * roaming on the same channel. until we will
3769 * have a better flow...)
3770 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003771 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3772 ret = wl12xx_croc(wl,
3773 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003774 if (ret < 0)
3775 goto out;
3776 }
3777
Eliad Peller0603d892011-10-05 11:55:51 +02003778 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003779 if (!(conf_flags & IEEE80211_CONF_IDLE))
3780 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003781 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003782 }
3783 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003784
Eliad Pellerd192d262011-05-24 14:33:08 +03003785 if (changed & BSS_CHANGED_IBSS) {
3786 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3787 bss_conf->ibss_joined);
3788
3789 if (bss_conf->ibss_joined) {
3790 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003791 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003792 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003793 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003794 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003795 wl1271_tx_min_rate_get(wl,
3796 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003797
Shahar Levi06b660e2011-09-05 13:54:36 +03003798 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003799 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3800 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003801 if (ret < 0)
3802 goto out;
3803 }
3804 }
3805
Eliad Peller0603d892011-10-05 11:55:51 +02003806 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003807 if (ret < 0)
3808 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003809
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003810 if (changed & BSS_CHANGED_ARP_FILTER) {
3811 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003812 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003813
Eliad Pellerc5312772010-12-09 11:31:27 +02003814 if (bss_conf->arp_addr_cnt == 1 &&
3815 bss_conf->arp_filter_enabled) {
3816 /*
3817 * The template should have been configured only upon
3818 * association. however, it seems that the correct ip
3819 * isn't being set (when sending), so we have to
3820 * reconfigure the template upon every ip change.
3821 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003822 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003823 if (ret < 0) {
3824 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003825 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003826 }
3827
Eliad Peller0603d892011-10-05 11:55:51 +02003828 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003829 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003830 addr);
3831 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003832 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003833
3834 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003835 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003836 }
3837
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003838 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003839 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003840 if (ret < 0) {
3841 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003842 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003843 }
Eliad Peller251c1772011-08-14 13:17:17 +03003844
3845 /* ROC until connected (after EAPOL exchange) */
3846 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003847 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003848 if (ret < 0)
3849 goto out;
3850
Eliad Pellerba8447f2011-10-10 10:13:00 +02003851 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003852 ieee80211_get_operstate(vif));
3853 }
3854 /*
3855 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003856 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003857 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003858 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003859 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003860 if (ret < 0)
3861 goto out;
3862 }
Eliad Peller05dba352011-08-23 16:37:01 +03003863
3864 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003865 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3866 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003867 enum wl1271_cmd_ps_mode mode;
3868
3869 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003870 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003871 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003872 true);
3873 if (ret < 0)
3874 goto out;
3875 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003876 }
3877
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003878 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003879 if (sta_exists) {
3880 if ((changed & BSS_CHANGED_HT) &&
3881 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003882 ret = wl1271_acx_set_ht_capabilities(wl,
3883 &sta_ht_cap,
3884 true,
Eliad Peller154da672011-10-05 11:55:53 +02003885 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003886 if (ret < 0) {
3887 wl1271_warning("Set ht cap true failed %d",
3888 ret);
3889 goto out;
3890 }
3891 }
3892 /* handle new association without HT and disassociation */
3893 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003894 ret = wl1271_acx_set_ht_capabilities(wl,
3895 &sta_ht_cap,
3896 false,
Eliad Peller154da672011-10-05 11:55:53 +02003897 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003898 if (ret < 0) {
3899 wl1271_warning("Set ht cap false failed %d",
3900 ret);
3901 goto out;
3902 }
3903 }
3904 }
3905
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003906 /* Handle HT information change. Done after join. */
3907 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003908 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003909 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003910 bss_conf->ht_operation_mode);
3911 if (ret < 0) {
3912 wl1271_warning("Set ht information failed %d", ret);
3913 goto out;
3914 }
3915 }
3916
Arik Nemtsove78a2872010-10-16 19:07:21 +02003917out:
3918 return;
3919}
3920
3921static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3922 struct ieee80211_vif *vif,
3923 struct ieee80211_bss_conf *bss_conf,
3924 u32 changed)
3925{
3926 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003927 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3928 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003929 int ret;
3930
3931 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3932 (int)changed);
3933
3934 mutex_lock(&wl->mutex);
3935
3936 if (unlikely(wl->state == WL1271_STATE_OFF))
3937 goto out;
3938
Eliad Peller10c8cd02011-10-10 10:13:06 +02003939 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3940 goto out;
3941
Ido Yariva6208652011-03-01 15:14:41 +02003942 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003943 if (ret < 0)
3944 goto out;
3945
3946 if (is_ap)
3947 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3948 else
3949 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3950
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003951 wl1271_ps_elp_sleep(wl);
3952
3953out:
3954 mutex_unlock(&wl->mutex);
3955}
3956
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003957static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3958 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003959 const struct ieee80211_tx_queue_params *params)
3960{
3961 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003962 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003963 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003964 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003965
3966 mutex_lock(&wl->mutex);
3967
3968 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3969
Kalle Valo4695dc92010-03-18 12:26:38 +02003970 if (params->uapsd)
3971 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3972 else
3973 ps_scheme = CONF_PS_SCHEME_LEGACY;
3974
Eliad Peller5b37ddf2011-12-18 20:25:40 +02003975 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003976 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003977
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003978 ret = wl1271_ps_elp_wakeup(wl);
3979 if (ret < 0)
3980 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003981
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003982 /*
3983 * the txop is confed in units of 32us by the mac80211,
3984 * we need us
3985 */
Eliad Peller0603d892011-10-05 11:55:51 +02003986 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003987 params->cw_min, params->cw_max,
3988 params->aifs, params->txop << 5);
3989 if (ret < 0)
3990 goto out_sleep;
3991
Eliad Peller0603d892011-10-05 11:55:51 +02003992 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003993 CONF_CHANNEL_TYPE_EDCF,
3994 wl1271_tx_get_queue(queue),
3995 ps_scheme, CONF_ACK_POLICY_LEGACY,
3996 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003997
3998out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003999 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004000
4001out:
4002 mutex_unlock(&wl->mutex);
4003
4004 return ret;
4005}
4006
Eliad Peller37a41b42011-09-21 14:06:11 +03004007static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4008 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004009{
4010
4011 struct wl1271 *wl = hw->priv;
4012 u64 mactime = ULLONG_MAX;
4013 int ret;
4014
4015 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4016
4017 mutex_lock(&wl->mutex);
4018
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004019 if (unlikely(wl->state == WL1271_STATE_OFF))
4020 goto out;
4021
Ido Yariva6208652011-03-01 15:14:41 +02004022 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004023 if (ret < 0)
4024 goto out;
4025
4026 ret = wl1271_acx_tsf_info(wl, &mactime);
4027 if (ret < 0)
4028 goto out_sleep;
4029
4030out_sleep:
4031 wl1271_ps_elp_sleep(wl);
4032
4033out:
4034 mutex_unlock(&wl->mutex);
4035 return mactime;
4036}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004037
John W. Linvilleece550d2010-07-28 16:41:06 -04004038static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4039 struct survey_info *survey)
4040{
4041 struct wl1271 *wl = hw->priv;
4042 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004043
John W. Linvilleece550d2010-07-28 16:41:06 -04004044 if (idx != 0)
4045 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004046
John W. Linvilleece550d2010-07-28 16:41:06 -04004047 survey->channel = conf->channel;
4048 survey->filled = SURVEY_INFO_NOISE_DBM;
4049 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004050
John W. Linvilleece550d2010-07-28 16:41:06 -04004051 return 0;
4052}
4053
Arik Nemtsov409622e2011-02-23 00:22:29 +02004054static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004055 struct wl12xx_vif *wlvif,
4056 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004057{
4058 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004059 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004060
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004061
4062 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004063 wl1271_warning("could not allocate HLID - too much stations");
4064 return -EBUSY;
4065 }
4066
4067 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004068 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4069 if (ret < 0) {
4070 wl1271_warning("could not allocate HLID - too many links");
4071 return -EBUSY;
4072 }
4073
4074 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004075 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004076 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004077 return 0;
4078}
4079
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004080void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004081{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004082 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004083 return;
4084
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004085 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004086 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004087 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004088 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004089 __clear_bit(hlid, &wl->ap_ps_map);
4090 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004091 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004092 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004093}
4094
4095static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4096 struct ieee80211_vif *vif,
4097 struct ieee80211_sta *sta)
4098{
4099 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004100 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004101 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004102 int ret = 0;
4103 u8 hlid;
4104
4105 mutex_lock(&wl->mutex);
4106
4107 if (unlikely(wl->state == WL1271_STATE_OFF))
4108 goto out;
4109
Eliad Peller536129c2011-10-05 11:55:45 +02004110 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004111 goto out;
4112
4113 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4114
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004115 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004116 if (ret < 0)
4117 goto out;
4118
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004119 wl_sta = (struct wl1271_station *)sta->drv_priv;
4120 hlid = wl_sta->hlid;
4121
Ido Yariva6208652011-03-01 15:14:41 +02004122 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004123 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004124 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004125
Eliad Peller1b92f152011-10-10 10:13:09 +02004126 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004127 if (ret < 0)
4128 goto out_sleep;
4129
Eliad Pellerb67476e2011-08-14 13:17:23 +03004130 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4131 if (ret < 0)
4132 goto out_sleep;
4133
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004134 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4135 if (ret < 0)
4136 goto out_sleep;
4137
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004138out_sleep:
4139 wl1271_ps_elp_sleep(wl);
4140
Arik Nemtsov409622e2011-02-23 00:22:29 +02004141out_free_sta:
4142 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004143 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004144
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004145out:
4146 mutex_unlock(&wl->mutex);
4147 return ret;
4148}
4149
4150static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4151 struct ieee80211_vif *vif,
4152 struct ieee80211_sta *sta)
4153{
4154 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004155 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004156 struct wl1271_station *wl_sta;
4157 int ret = 0, id;
4158
4159 mutex_lock(&wl->mutex);
4160
4161 if (unlikely(wl->state == WL1271_STATE_OFF))
4162 goto out;
4163
Eliad Peller536129c2011-10-05 11:55:45 +02004164 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004165 goto out;
4166
4167 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4168
4169 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004170 id = wl_sta->hlid;
4171 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004172 goto out;
4173
Ido Yariva6208652011-03-01 15:14:41 +02004174 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004175 if (ret < 0)
4176 goto out;
4177
Eliad Pellerc690ec82011-08-14 13:17:07 +03004178 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004179 if (ret < 0)
4180 goto out_sleep;
4181
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004182 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004183
4184out_sleep:
4185 wl1271_ps_elp_sleep(wl);
4186
4187out:
4188 mutex_unlock(&wl->mutex);
4189 return ret;
4190}
4191
Luciano Coelho4623ec72011-03-21 19:26:41 +02004192static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4193 struct ieee80211_vif *vif,
4194 enum ieee80211_ampdu_mlme_action action,
4195 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4196 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004197{
4198 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004199 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004200 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004201 u8 hlid, *ba_bitmap;
4202
4203 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4204 tid);
4205
4206 /* sanity check - the fields in FW are only 8bits wide */
4207 if (WARN_ON(tid > 0xFF))
4208 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004209
4210 mutex_lock(&wl->mutex);
4211
4212 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4213 ret = -EAGAIN;
4214 goto out;
4215 }
4216
Eliad Peller536129c2011-10-05 11:55:45 +02004217 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004218 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004219 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004220 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004221 struct wl1271_station *wl_sta;
4222
4223 wl_sta = (struct wl1271_station *)sta->drv_priv;
4224 hlid = wl_sta->hlid;
4225 ba_bitmap = &wl->links[hlid].ba_bitmap;
4226 } else {
4227 ret = -EINVAL;
4228 goto out;
4229 }
4230
Ido Yariva6208652011-03-01 15:14:41 +02004231 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004232 if (ret < 0)
4233 goto out;
4234
Shahar Levi70559a02011-05-22 16:10:22 +03004235 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4236 tid, action);
4237
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004238 switch (action) {
4239 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004240 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004241 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004242 break;
4243 }
4244
4245 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4246 ret = -EBUSY;
4247 wl1271_error("exceeded max RX BA sessions");
4248 break;
4249 }
4250
4251 if (*ba_bitmap & BIT(tid)) {
4252 ret = -EINVAL;
4253 wl1271_error("cannot enable RX BA session on active "
4254 "tid: %d", tid);
4255 break;
4256 }
4257
4258 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4259 hlid);
4260 if (!ret) {
4261 *ba_bitmap |= BIT(tid);
4262 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004263 }
4264 break;
4265
4266 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004267 if (!(*ba_bitmap & BIT(tid))) {
4268 ret = -EINVAL;
4269 wl1271_error("no active RX BA session on tid: %d",
4270 tid);
4271 break;
4272 }
4273
4274 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4275 hlid);
4276 if (!ret) {
4277 *ba_bitmap &= ~BIT(tid);
4278 wl->ba_rx_session_count--;
4279 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004280 break;
4281
4282 /*
4283 * The BA initiator session management in FW independently.
4284 * Falling break here on purpose for all TX APDU commands.
4285 */
4286 case IEEE80211_AMPDU_TX_START:
4287 case IEEE80211_AMPDU_TX_STOP:
4288 case IEEE80211_AMPDU_TX_OPERATIONAL:
4289 ret = -EINVAL;
4290 break;
4291
4292 default:
4293 wl1271_error("Incorrect ampdu action id=%x\n", action);
4294 ret = -EINVAL;
4295 }
4296
4297 wl1271_ps_elp_sleep(wl);
4298
4299out:
4300 mutex_unlock(&wl->mutex);
4301
4302 return ret;
4303}
4304
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004305static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4306 struct ieee80211_vif *vif,
4307 const struct cfg80211_bitrate_mask *mask)
4308{
Eliad Peller83587502011-10-10 10:12:53 +02004309 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004310 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004311 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004312
4313 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4314 mask->control[NL80211_BAND_2GHZ].legacy,
4315 mask->control[NL80211_BAND_5GHZ].legacy);
4316
4317 mutex_lock(&wl->mutex);
4318
4319 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004320 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004321 wl1271_tx_enabled_rates_get(wl,
4322 mask->control[i].legacy,
4323 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004324
4325 if (unlikely(wl->state == WL1271_STATE_OFF))
4326 goto out;
4327
4328 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4329 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4330
4331 ret = wl1271_ps_elp_wakeup(wl);
4332 if (ret < 0)
4333 goto out;
4334
4335 wl1271_set_band_rate(wl, wlvif);
4336 wlvif->basic_rate =
4337 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4338 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4339
4340 wl1271_ps_elp_sleep(wl);
4341 }
4342out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004343 mutex_unlock(&wl->mutex);
4344
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004345 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004346}
4347
Shahar Levi6d158ff2011-09-08 13:01:33 +03004348static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4349 struct ieee80211_channel_switch *ch_switch)
4350{
4351 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004352 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004353 int ret;
4354
4355 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4356
4357 mutex_lock(&wl->mutex);
4358
4359 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004360 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4361 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4362 ieee80211_chswitch_done(vif, false);
4363 }
4364 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004365 }
4366
4367 ret = wl1271_ps_elp_wakeup(wl);
4368 if (ret < 0)
4369 goto out;
4370
Eliad Peller52630c52011-10-10 10:13:08 +02004371 /* TODO: change mac80211 to pass vif as param */
4372 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4373 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004374
Eliad Peller52630c52011-10-10 10:13:08 +02004375 if (!ret)
4376 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4377 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004378
4379 wl1271_ps_elp_sleep(wl);
4380
4381out:
4382 mutex_unlock(&wl->mutex);
4383}
4384
Arik Nemtsov33437892011-04-26 23:35:39 +03004385static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4386{
4387 struct wl1271 *wl = hw->priv;
4388 bool ret = false;
4389
4390 mutex_lock(&wl->mutex);
4391
4392 if (unlikely(wl->state == WL1271_STATE_OFF))
4393 goto out;
4394
4395 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004396 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004397out:
4398 mutex_unlock(&wl->mutex);
4399
4400 return ret;
4401}
4402
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004403/* can't be const, mac80211 writes to this */
4404static struct ieee80211_rate wl1271_rates[] = {
4405 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004406 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4407 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004408 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004409 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4410 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004411 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4412 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004413 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4414 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004415 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4416 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004417 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4418 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004419 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4420 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004421 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4422 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004423 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004424 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4425 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004426 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004427 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4428 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004429 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004430 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4431 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004432 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004433 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4434 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004435 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004436 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4437 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004438 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004439 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4440 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004441 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004442 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4443 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004444};
4445
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004446/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004447static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004448 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004449 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004450 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4451 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4452 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004453 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004454 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4455 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4456 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004457 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004458 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4459 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4460 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004461 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004462};
4463
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004464/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004465static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004466 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004467 7, /* CONF_HW_RXTX_RATE_MCS7 */
4468 6, /* CONF_HW_RXTX_RATE_MCS6 */
4469 5, /* CONF_HW_RXTX_RATE_MCS5 */
4470 4, /* CONF_HW_RXTX_RATE_MCS4 */
4471 3, /* CONF_HW_RXTX_RATE_MCS3 */
4472 2, /* CONF_HW_RXTX_RATE_MCS2 */
4473 1, /* CONF_HW_RXTX_RATE_MCS1 */
4474 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004475
4476 11, /* CONF_HW_RXTX_RATE_54 */
4477 10, /* CONF_HW_RXTX_RATE_48 */
4478 9, /* CONF_HW_RXTX_RATE_36 */
4479 8, /* CONF_HW_RXTX_RATE_24 */
4480
4481 /* TI-specific rate */
4482 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4483
4484 7, /* CONF_HW_RXTX_RATE_18 */
4485 6, /* CONF_HW_RXTX_RATE_12 */
4486 3, /* CONF_HW_RXTX_RATE_11 */
4487 5, /* CONF_HW_RXTX_RATE_9 */
4488 4, /* CONF_HW_RXTX_RATE_6 */
4489 2, /* CONF_HW_RXTX_RATE_5_5 */
4490 1, /* CONF_HW_RXTX_RATE_2 */
4491 0 /* CONF_HW_RXTX_RATE_1 */
4492};
4493
Shahar Levie8b03a22010-10-13 16:09:39 +02004494/* 11n STA capabilities */
4495#define HW_RX_HIGHEST_RATE 72
4496
Shahar Levi00d20102010-11-08 11:20:10 +00004497#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004498 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4499 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004500 .ht_supported = true, \
4501 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4502 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4503 .mcs = { \
4504 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4505 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4506 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4507 }, \
4508}
4509
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004510/* can't be const, mac80211 writes to this */
4511static struct ieee80211_supported_band wl1271_band_2ghz = {
4512 .channels = wl1271_channels,
4513 .n_channels = ARRAY_SIZE(wl1271_channels),
4514 .bitrates = wl1271_rates,
4515 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004516 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004517};
4518
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004519/* 5 GHz data rates for WL1273 */
4520static struct ieee80211_rate wl1271_rates_5ghz[] = {
4521 { .bitrate = 60,
4522 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4523 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4524 { .bitrate = 90,
4525 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4526 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4527 { .bitrate = 120,
4528 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4529 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4530 { .bitrate = 180,
4531 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4532 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4533 { .bitrate = 240,
4534 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4535 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4536 { .bitrate = 360,
4537 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4538 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4539 { .bitrate = 480,
4540 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4541 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4542 { .bitrate = 540,
4543 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4544 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4545};
4546
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004547/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004548static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004549 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4550 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4551 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4552 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4553 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4554 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4555 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4556 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4557 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4558 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4559 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4560 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4561 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4562 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4563 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4564 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4565 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4566 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4567 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4568 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4569 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4570 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4571 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4572 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4573 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4574 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4575 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4576 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4577 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4578 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4579 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4580 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4581 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4582 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004583};
4584
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004585/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004586static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004587 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004588 7, /* CONF_HW_RXTX_RATE_MCS7 */
4589 6, /* CONF_HW_RXTX_RATE_MCS6 */
4590 5, /* CONF_HW_RXTX_RATE_MCS5 */
4591 4, /* CONF_HW_RXTX_RATE_MCS4 */
4592 3, /* CONF_HW_RXTX_RATE_MCS3 */
4593 2, /* CONF_HW_RXTX_RATE_MCS2 */
4594 1, /* CONF_HW_RXTX_RATE_MCS1 */
4595 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004596
4597 7, /* CONF_HW_RXTX_RATE_54 */
4598 6, /* CONF_HW_RXTX_RATE_48 */
4599 5, /* CONF_HW_RXTX_RATE_36 */
4600 4, /* CONF_HW_RXTX_RATE_24 */
4601
4602 /* TI-specific rate */
4603 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4604
4605 3, /* CONF_HW_RXTX_RATE_18 */
4606 2, /* CONF_HW_RXTX_RATE_12 */
4607 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4608 1, /* CONF_HW_RXTX_RATE_9 */
4609 0, /* CONF_HW_RXTX_RATE_6 */
4610 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4611 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4612 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4613};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004614
4615static struct ieee80211_supported_band wl1271_band_5ghz = {
4616 .channels = wl1271_channels_5ghz,
4617 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4618 .bitrates = wl1271_rates_5ghz,
4619 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004620 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004621};
4622
Tobias Klausera0ea9492010-05-20 10:38:11 +02004623static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004624 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4625 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4626};
4627
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004628static const struct ieee80211_ops wl1271_ops = {
4629 .start = wl1271_op_start,
4630 .stop = wl1271_op_stop,
4631 .add_interface = wl1271_op_add_interface,
4632 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004633 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004634#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004635 .suspend = wl1271_op_suspend,
4636 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004637#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004638 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004639 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004640 .configure_filter = wl1271_op_configure_filter,
4641 .tx = wl1271_op_tx,
4642 .set_key = wl1271_op_set_key,
4643 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004644 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004645 .sched_scan_start = wl1271_op_sched_scan_start,
4646 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004647 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004648 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004649 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004650 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004651 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004652 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004653 .sta_add = wl1271_op_sta_add,
4654 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004655 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004656 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004657 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004658 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004659 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004660};
4661
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004662
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004663u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004664{
4665 u8 idx;
4666
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004667 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004668
4669 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4670 wl1271_error("Illegal RX rate from HW: %d", rate);
4671 return 0;
4672 }
4673
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004674 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004675 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4676 wl1271_error("Unsupported RX rate from HW: %d", rate);
4677 return 0;
4678 }
4679
4680 return idx;
4681}
4682
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004683static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4684 struct device_attribute *attr,
4685 char *buf)
4686{
4687 struct wl1271 *wl = dev_get_drvdata(dev);
4688 ssize_t len;
4689
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004690 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004691
4692 mutex_lock(&wl->mutex);
4693 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4694 wl->sg_enabled);
4695 mutex_unlock(&wl->mutex);
4696
4697 return len;
4698
4699}
4700
4701static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4702 struct device_attribute *attr,
4703 const char *buf, size_t count)
4704{
4705 struct wl1271 *wl = dev_get_drvdata(dev);
4706 unsigned long res;
4707 int ret;
4708
Luciano Coelho6277ed62011-04-01 17:49:54 +03004709 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004710 if (ret < 0) {
4711 wl1271_warning("incorrect value written to bt_coex_mode");
4712 return count;
4713 }
4714
4715 mutex_lock(&wl->mutex);
4716
4717 res = !!res;
4718
4719 if (res == wl->sg_enabled)
4720 goto out;
4721
4722 wl->sg_enabled = res;
4723
4724 if (wl->state == WL1271_STATE_OFF)
4725 goto out;
4726
Ido Yariva6208652011-03-01 15:14:41 +02004727 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004728 if (ret < 0)
4729 goto out;
4730
4731 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4732 wl1271_ps_elp_sleep(wl);
4733
4734 out:
4735 mutex_unlock(&wl->mutex);
4736 return count;
4737}
4738
4739static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4740 wl1271_sysfs_show_bt_coex_state,
4741 wl1271_sysfs_store_bt_coex_state);
4742
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004743static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4744 struct device_attribute *attr,
4745 char *buf)
4746{
4747 struct wl1271 *wl = dev_get_drvdata(dev);
4748 ssize_t len;
4749
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004750 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004751
4752 mutex_lock(&wl->mutex);
4753 if (wl->hw_pg_ver >= 0)
4754 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4755 else
4756 len = snprintf(buf, len, "n/a\n");
4757 mutex_unlock(&wl->mutex);
4758
4759 return len;
4760}
4761
Gery Kahn6f07b722011-07-18 14:21:49 +03004762static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004763 wl1271_sysfs_show_hw_pg_ver, NULL);
4764
Ido Yariv95dac04f2011-06-06 14:57:06 +03004765static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4766 struct bin_attribute *bin_attr,
4767 char *buffer, loff_t pos, size_t count)
4768{
4769 struct device *dev = container_of(kobj, struct device, kobj);
4770 struct wl1271 *wl = dev_get_drvdata(dev);
4771 ssize_t len;
4772 int ret;
4773
4774 ret = mutex_lock_interruptible(&wl->mutex);
4775 if (ret < 0)
4776 return -ERESTARTSYS;
4777
4778 /* Let only one thread read the log at a time, blocking others */
4779 while (wl->fwlog_size == 0) {
4780 DEFINE_WAIT(wait);
4781
4782 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4783 &wait,
4784 TASK_INTERRUPTIBLE);
4785
4786 if (wl->fwlog_size != 0) {
4787 finish_wait(&wl->fwlog_waitq, &wait);
4788 break;
4789 }
4790
4791 mutex_unlock(&wl->mutex);
4792
4793 schedule();
4794 finish_wait(&wl->fwlog_waitq, &wait);
4795
4796 if (signal_pending(current))
4797 return -ERESTARTSYS;
4798
4799 ret = mutex_lock_interruptible(&wl->mutex);
4800 if (ret < 0)
4801 return -ERESTARTSYS;
4802 }
4803
4804 /* Check if the fwlog is still valid */
4805 if (wl->fwlog_size < 0) {
4806 mutex_unlock(&wl->mutex);
4807 return 0;
4808 }
4809
4810 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4811 len = min(count, (size_t)wl->fwlog_size);
4812 wl->fwlog_size -= len;
4813 memcpy(buffer, wl->fwlog, len);
4814
4815 /* Make room for new messages */
4816 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4817
4818 mutex_unlock(&wl->mutex);
4819
4820 return len;
4821}
4822
4823static struct bin_attribute fwlog_attr = {
4824 .attr = {.name = "fwlog", .mode = S_IRUSR},
4825 .read = wl1271_sysfs_read_fwlog,
4826};
4827
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004828static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004829{
4830 int ret;
4831
4832 if (wl->mac80211_registered)
4833 return 0;
4834
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004835 ret = wl1271_fetch_nvs(wl);
4836 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004837 /* NOTE: The wl->nvs->nvs element must be first, in
4838 * order to simplify the casting, we assume it is at
4839 * the beginning of the wl->nvs structure.
4840 */
4841 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004842
4843 wl->mac_addr[0] = nvs_ptr[11];
4844 wl->mac_addr[1] = nvs_ptr[10];
4845 wl->mac_addr[2] = nvs_ptr[6];
4846 wl->mac_addr[3] = nvs_ptr[5];
4847 wl->mac_addr[4] = nvs_ptr[4];
4848 wl->mac_addr[5] = nvs_ptr[3];
4849 }
4850
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004851 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4852
4853 ret = ieee80211_register_hw(wl->hw);
4854 if (ret < 0) {
4855 wl1271_error("unable to register mac80211 hw: %d", ret);
4856 return ret;
4857 }
4858
4859 wl->mac80211_registered = true;
4860
Eliad Pellerd60080a2010-11-24 12:53:16 +02004861 wl1271_debugfs_init(wl);
4862
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004863 register_netdevice_notifier(&wl1271_dev_notifier);
4864
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004865 wl1271_notice("loaded");
4866
4867 return 0;
4868}
4869
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004870static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004871{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004872 if (wl->state == WL1271_STATE_PLT)
4873 __wl1271_plt_stop(wl);
4874
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004875 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004876 ieee80211_unregister_hw(wl->hw);
4877 wl->mac80211_registered = false;
4878
4879}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004880
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004881static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004882{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004883 static const u32 cipher_suites[] = {
4884 WLAN_CIPHER_SUITE_WEP40,
4885 WLAN_CIPHER_SUITE_WEP104,
4886 WLAN_CIPHER_SUITE_TKIP,
4887 WLAN_CIPHER_SUITE_CCMP,
4888 WL1271_CIPHER_SUITE_GEM,
4889 };
4890
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004891 /* The tx descriptor buffer and the TKIP space. */
4892 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4893 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004894
4895 /* unit us */
4896 /* FIXME: find a proper value */
4897 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004898 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004899
4900 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004901 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004902 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004903 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004904 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004905 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004906 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004907 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004908 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004909 IEEE80211_HW_AP_LINK_PS |
4910 IEEE80211_HW_AMPDU_AGGREGATION |
4911 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004912
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004913 wl->hw->wiphy->cipher_suites = cipher_suites;
4914 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4915
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004916 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004917 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4918 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004919 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004920 wl->hw->wiphy->max_sched_scan_ssids = 16;
4921 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004922 /*
4923 * Maximum length of elements in scanning probe request templates
4924 * should be the maximum length possible for a template, without
4925 * the IEEE80211 header of the template
4926 */
Eliad Peller154037d2011-08-14 13:17:12 +03004927 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004928 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004929
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004930 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4931 sizeof(struct ieee80211_header);
4932
Eliad Peller1ec23f72011-08-25 14:26:54 +03004933 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4934
Luciano Coelho4a31c112011-03-21 23:16:14 +02004935 /* make sure all our channels fit in the scanned_ch bitmask */
4936 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4937 ARRAY_SIZE(wl1271_channels_5ghz) >
4938 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004939 /*
4940 * We keep local copies of the band structs because we need to
4941 * modify them on a per-device basis.
4942 */
4943 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4944 sizeof(wl1271_band_2ghz));
4945 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4946 sizeof(wl1271_band_5ghz));
4947
4948 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4949 &wl->bands[IEEE80211_BAND_2GHZ];
4950 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4951 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004952
Kalle Valo12bd8942010-03-18 12:26:33 +02004953 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004954 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004955
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004956 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4957
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02004958 /* the FW answers probe-requests in AP-mode */
4959 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
4960 wl->hw->wiphy->probe_resp_offload =
4961 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
4962 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
4963 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
4964
Felipe Balbia390e852011-10-06 10:07:44 +03004965 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004966
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004967 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004968 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004969
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004970 wl->hw->max_rx_aggregation_subframes = 8;
4971
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004972 return 0;
4973}
4974
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004975#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004976
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004977static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004978{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004979 struct ieee80211_hw *hw;
4980 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004981 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004982 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004983
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004984 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004985
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004986 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4987 if (!hw) {
4988 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004989 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004990 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004991 }
4992
4993 wl = hw->priv;
4994 memset(wl, 0, sizeof(*wl));
4995
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004996 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02004997 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004998
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004999 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005000
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005001 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005002 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005003 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5004
Ido Yariva6208652011-03-01 15:14:41 +02005005 skb_queue_head_init(&wl->deferred_rx_queue);
5006 skb_queue_head_init(&wl->deferred_tx_queue);
5007
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005008 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005009 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005010 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5011 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5012 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005013
Eliad Peller92ef8962011-06-07 12:50:46 +03005014 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5015 if (!wl->freezable_wq) {
5016 ret = -ENOMEM;
5017 goto err_hw;
5018 }
5019
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005020 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005021 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005022 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005023 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005024 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005025 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005026 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005027 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005028 wl->ap_ps_map = 0;
5029 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005030 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005031 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005032 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005033 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005034 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005035 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005036 wl->fwlog_size = 0;
5037 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005038
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005039 /* The system link is always allocated */
5040 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5041
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005042 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005043 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005044 wl->tx_frames[i] = NULL;
5045
5046 spin_lock_init(&wl->wl_lock);
5047
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005048 wl->state = WL1271_STATE_OFF;
5049 mutex_init(&wl->mutex);
5050
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005051 /* Apply default driver configuration. */
5052 wl1271_conf_init(wl);
5053
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005054 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5055 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5056 if (!wl->aggr_buf) {
5057 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005058 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005059 }
5060
Ido Yariv990f5de2011-03-31 10:06:59 +02005061 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5062 if (!wl->dummy_packet) {
5063 ret = -ENOMEM;
5064 goto err_aggr;
5065 }
5066
Ido Yariv95dac04f2011-06-06 14:57:06 +03005067 /* Allocate one page for the FW log */
5068 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5069 if (!wl->fwlog) {
5070 ret = -ENOMEM;
5071 goto err_dummy_packet;
5072 }
5073
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005074 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005075
Ido Yariv990f5de2011-03-31 10:06:59 +02005076err_dummy_packet:
5077 dev_kfree_skb(wl->dummy_packet);
5078
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005079err_aggr:
5080 free_pages((unsigned long)wl->aggr_buf, order);
5081
Eliad Peller92ef8962011-06-07 12:50:46 +03005082err_wq:
5083 destroy_workqueue(wl->freezable_wq);
5084
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005085err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005086 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005087 ieee80211_free_hw(hw);
5088
5089err_hw_alloc:
5090
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005091 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005092}
5093
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005094static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005095{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005096 /* Unblock any fwlog readers */
5097 mutex_lock(&wl->mutex);
5098 wl->fwlog_size = -1;
5099 wake_up_interruptible_all(&wl->fwlog_waitq);
5100 mutex_unlock(&wl->mutex);
5101
Felipe Balbif79f8902011-10-06 13:05:25 +03005102 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005103
Felipe Balbif79f8902011-10-06 13:05:25 +03005104 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005105
Felipe Balbif79f8902011-10-06 13:05:25 +03005106 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005107 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005108 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005109 free_pages((unsigned long)wl->aggr_buf,
5110 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005111
5112 wl1271_debugfs_exit(wl);
5113
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005114 vfree(wl->fw);
5115 wl->fw = NULL;
5116 kfree(wl->nvs);
5117 wl->nvs = NULL;
5118
5119 kfree(wl->fw_status);
5120 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005121 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005122
5123 ieee80211_free_hw(wl->hw);
5124
5125 return 0;
5126}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005127
Felipe Balbia390e852011-10-06 10:07:44 +03005128static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5129{
5130 struct wl1271 *wl = cookie;
5131 unsigned long flags;
5132
5133 wl1271_debug(DEBUG_IRQ, "IRQ");
5134
5135 /* complete the ELP completion */
5136 spin_lock_irqsave(&wl->wl_lock, flags);
5137 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5138 if (wl->elp_compl) {
5139 complete(wl->elp_compl);
5140 wl->elp_compl = NULL;
5141 }
5142
5143 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5144 /* don't enqueue a work right now. mark it as pending */
5145 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5146 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5147 disable_irq_nosync(wl->irq);
5148 pm_wakeup_event(wl->dev, 0);
5149 spin_unlock_irqrestore(&wl->wl_lock, flags);
5150 return IRQ_HANDLED;
5151 }
5152 spin_unlock_irqrestore(&wl->wl_lock, flags);
5153
5154 return IRQ_WAKE_THREAD;
5155}
5156
Felipe Balbice2a2172011-10-05 14:12:55 +03005157static int __devinit wl12xx_probe(struct platform_device *pdev)
5158{
Felipe Balbia390e852011-10-06 10:07:44 +03005159 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5160 struct ieee80211_hw *hw;
5161 struct wl1271 *wl;
5162 unsigned long irqflags;
5163 int ret = -ENODEV;
5164
5165 hw = wl1271_alloc_hw();
5166 if (IS_ERR(hw)) {
5167 wl1271_error("can't allocate hw");
5168 ret = PTR_ERR(hw);
5169 goto out;
5170 }
5171
5172 wl = hw->priv;
5173 wl->irq = platform_get_irq(pdev, 0);
5174 wl->ref_clock = pdata->board_ref_clock;
5175 wl->tcxo_clock = pdata->board_tcxo_clock;
5176 wl->platform_quirks = pdata->platform_quirks;
5177 wl->set_power = pdata->set_power;
5178 wl->dev = &pdev->dev;
5179 wl->if_ops = pdata->ops;
5180
5181 platform_set_drvdata(pdev, wl);
5182
5183 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5184 irqflags = IRQF_TRIGGER_RISING;
5185 else
5186 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5187
5188 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5189 irqflags,
5190 pdev->name, wl);
5191 if (ret < 0) {
5192 wl1271_error("request_irq() failed: %d", ret);
5193 goto out_free_hw;
5194 }
5195
5196 ret = enable_irq_wake(wl->irq);
5197 if (!ret) {
5198 wl->irq_wake_enabled = true;
5199 device_init_wakeup(wl->dev, 1);
5200 if (pdata->pwr_in_suspend)
5201 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5202
5203 }
5204 disable_irq(wl->irq);
5205
5206 ret = wl1271_init_ieee80211(wl);
5207 if (ret)
5208 goto out_irq;
5209
5210 ret = wl1271_register_hw(wl);
5211 if (ret)
5212 goto out_irq;
5213
Felipe Balbif79f8902011-10-06 13:05:25 +03005214 /* Create sysfs file to control bt coex state */
5215 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5216 if (ret < 0) {
5217 wl1271_error("failed to create sysfs file bt_coex_state");
5218 goto out_irq;
5219 }
5220
5221 /* Create sysfs file to get HW PG version */
5222 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5223 if (ret < 0) {
5224 wl1271_error("failed to create sysfs file hw_pg_ver");
5225 goto out_bt_coex_state;
5226 }
5227
5228 /* Create sysfs file for the FW log */
5229 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5230 if (ret < 0) {
5231 wl1271_error("failed to create sysfs file fwlog");
5232 goto out_hw_pg_ver;
5233 }
5234
Felipe Balbice2a2172011-10-05 14:12:55 +03005235 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005236
Felipe Balbif79f8902011-10-06 13:05:25 +03005237out_hw_pg_ver:
5238 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5239
5240out_bt_coex_state:
5241 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5242
Felipe Balbia390e852011-10-06 10:07:44 +03005243out_irq:
5244 free_irq(wl->irq, wl);
5245
5246out_free_hw:
5247 wl1271_free_hw(wl);
5248
5249out:
5250 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005251}
5252
5253static int __devexit wl12xx_remove(struct platform_device *pdev)
5254{
Felipe Balbia390e852011-10-06 10:07:44 +03005255 struct wl1271 *wl = platform_get_drvdata(pdev);
5256
5257 if (wl->irq_wake_enabled) {
5258 device_init_wakeup(wl->dev, 0);
5259 disable_irq_wake(wl->irq);
5260 }
5261 wl1271_unregister_hw(wl);
5262 free_irq(wl->irq, wl);
5263 wl1271_free_hw(wl);
5264
Felipe Balbice2a2172011-10-05 14:12:55 +03005265 return 0;
5266}
5267
5268static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005269 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005270 { } /* Terminating Entry */
5271};
5272MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5273
5274static struct platform_driver wl12xx_driver = {
5275 .probe = wl12xx_probe,
5276 .remove = __devexit_p(wl12xx_remove),
5277 .id_table = wl12xx_id_table,
5278 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005279 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005280 .owner = THIS_MODULE,
5281 }
5282};
5283
5284static int __init wl12xx_init(void)
5285{
5286 return platform_driver_register(&wl12xx_driver);
5287}
5288module_init(wl12xx_init);
5289
5290static void __exit wl12xx_exit(void)
5291{
5292 platform_driver_unregister(&wl12xx_driver);
5293}
5294module_exit(wl12xx_exit);
5295
Guy Eilam491bbd62011-01-12 10:33:29 +01005296u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005297EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005298module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005299MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5300
Ido Yariv95dac04f2011-06-06 14:57:06 +03005301module_param_named(fwlog, fwlog_param, charp, 0);
5302MODULE_PARM_DESC(keymap,
5303 "FW logger options: continuous, ondemand, dbgpins or disable");
5304
Eliad Peller2a5bff02011-08-25 18:10:59 +03005305module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5306MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5307
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005308MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005309MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005310MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");