blob: 0719fc82d55f0a9c29d2087febc6bc49b2d12799 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Felipe Balbia390e852011-10-06 10:07:44 +030035#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "wl12xx.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030038#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030039#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000040#include "reg.h"
41#include "io.h"
42#include "event.h"
43#include "tx.h"
44#include "rx.h"
45#include "ps.h"
46#include "init.h"
47#include "debugfs.h"
48#include "cmd.h"
49#include "boot.h"
50#include "testmode.h"
51#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030052
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020053#define WL1271_BOOT_RETRIES 3
54
Juuso Oikarinen8a080482009-10-13 12:47:44 +030055static struct conf_drv_settings default_conf = {
56 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030057 .params = {
58 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
61 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
62 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
64 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
65 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
66 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
68 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
69 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
70 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
71 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
73 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
74 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
75 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
76 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
77 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
78 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
79 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
82 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
83 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
84 /* active scan params */
85 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
86 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
87 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
88 /* passive scan params */
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
91 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
92 /* passive scan in dual antenna params */
93 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
94 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
95 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
96 /* general params */
97 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
98 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
99 [CONF_SG_BEACON_MISS_PERCENT] = 60,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_RXT] = 1200,
102 [CONF_SG_TXT] = 1000,
103 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
104 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
105 [CONF_SG_HV3_MAX_SERVED] = 6,
106 [CONF_SG_PS_POLL_TIMEOUT] = 10,
107 [CONF_SG_UPSD_TIMEOUT] = 10,
108 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
109 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
110 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
111 /* AP params */
112 [CONF_AP_BEACON_MISS_TX] = 3,
113 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
114 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
115 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
116 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
117 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300118 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200119 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300120 },
121 .rx = {
122 .rx_msdu_life_time = 512000,
123 .packet_detection_threshold = 0,
124 .ps_poll_timeout = 15,
125 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300126 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200127 .rx_cca_threshold = 0,
128 .irq_blk_threshold = 0xFFFF,
129 .irq_pkt_threshold = 0,
130 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300131 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
132 },
133 .tx = {
134 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200135 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300136 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300137 .short_retry_limit = 10,
138 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200139 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300140 },
141 .ac_conf_count = 4,
142 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200143 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300144 .ac = CONF_TX_AC_BE,
145 .cw_min = 15,
146 .cw_max = 63,
147 .aifsn = 3,
148 .tx_op_limit = 0,
149 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200150 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300151 .ac = CONF_TX_AC_BK,
152 .cw_min = 15,
153 .cw_max = 63,
154 .aifsn = 7,
155 .tx_op_limit = 0,
156 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200157 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300158 .ac = CONF_TX_AC_VI,
159 .cw_min = 15,
160 .cw_max = 63,
161 .aifsn = CONF_TX_AIFS_PIFS,
162 .tx_op_limit = 3008,
163 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200164 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300165 .ac = CONF_TX_AC_VO,
166 .cw_min = 15,
167 .cw_max = 63,
168 .aifsn = CONF_TX_AIFS_PIFS,
169 .tx_op_limit = 1504,
170 },
171 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300172 .max_tx_retries = 100,
173 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300175 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200176 [CONF_TX_AC_BE] = {
177 .queue_id = CONF_TX_AC_BE,
178 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300179 .tsid = CONF_TX_AC_BE,
180 .ps_scheme = CONF_PS_SCHEME_LEGACY,
181 .ack_policy = CONF_ACK_POLICY_LEGACY,
182 .apsd_conf = {0, 0},
183 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200184 [CONF_TX_AC_BK] = {
185 .queue_id = CONF_TX_AC_BK,
186 .channel_type = CONF_CHANNEL_TYPE_EDCF,
187 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300188 .ps_scheme = CONF_PS_SCHEME_LEGACY,
189 .ack_policy = CONF_ACK_POLICY_LEGACY,
190 .apsd_conf = {0, 0},
191 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200192 [CONF_TX_AC_VI] = {
193 .queue_id = CONF_TX_AC_VI,
194 .channel_type = CONF_CHANNEL_TYPE_EDCF,
195 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .ps_scheme = CONF_PS_SCHEME_LEGACY,
197 .ack_policy = CONF_ACK_POLICY_LEGACY,
198 .apsd_conf = {0, 0},
199 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200200 [CONF_TX_AC_VO] = {
201 .queue_id = CONF_TX_AC_VO,
202 .channel_type = CONF_CHANNEL_TYPE_EDCF,
203 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300204 .ps_scheme = CONF_PS_SCHEME_LEGACY,
205 .ack_policy = CONF_ACK_POLICY_LEGACY,
206 .apsd_conf = {0, 0},
207 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300208 },
209 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200210 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300211 .tx_compl_threshold = 4,
212 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
213 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200214 .tmpl_short_retry_limit = 10,
215 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300216 },
217 .conn = {
218 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300219 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300221 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300222 .bcn_filt_ie = {
223 [0] = {
224 .ie = WLAN_EID_CHANNEL_SWITCH,
225 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300226 },
227 [1] = {
228 .ie = WLAN_EID_HT_INFORMATION,
229 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
230 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200232 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 .bss_lose_timeout = 100,
234 .beacon_rx_timeout = 10000,
235 .broadcast_timeout = 20000,
236 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300237 .ps_poll_threshold = 10,
238 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300239 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200240 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300241 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300242 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200243 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300244 .keep_alive_interval = 55000,
245 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300246 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200247 .itrim = {
248 .enable = false,
249 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200250 },
251 .pm_config = {
252 .host_clk_settling_time = 5000,
253 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 },
255 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300256 .trigger_pacing = 1,
257 .avg_weight_rssi_beacon = 20,
258 .avg_weight_rssi_data = 10,
259 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100260 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200261 },
262 .scan = {
263 .min_dwell_time_active = 7500,
264 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100265 .min_dwell_time_passive = 100000,
266 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200267 .num_probe_reqs = 2,
268 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300269 .sched_scan = {
270 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300271 .min_dwell_time_active = 30,
272 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300274 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300275 .num_probe_reqs = 2,
276 .rssi_threshold = -90,
277 .snr_threshold = 0,
278 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200279 .rf = {
280 .tx_per_channel_power_compensation_2 = {
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 },
283 .tx_per_channel_power_compensation_5 = {
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 },
288 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300290 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100291 .tx_ba_win_size = 64,
292 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300293 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100294 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200295 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200296 .num_stations = 1,
297 .ssid_profiles = 1,
298 .rx_block_num = 70,
299 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300300 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200301 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200302 .min_req_rx_blocks = 22,
303 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200304 },
305 .mem_wl128x = {
306 .num_stations = 1,
307 .ssid_profiles = 1,
308 .rx_block_num = 40,
309 .tx_min_block_num = 40,
310 .dynamic_memory = 1,
311 .min_req_tx_blocks = 45,
312 .min_req_rx_blocks = 22,
313 .tx_min = 27,
314 },
Shahar Leviff868432011-04-11 15:41:46 +0300315 .fm_coex = {
316 .enable = true,
317 .swallow_period = 5,
318 .n_divider_fref_set_1 = 0xff, /* default */
319 .n_divider_fref_set_2 = 12,
320 .m_divider_fref_set_1 = 148,
321 .m_divider_fref_set_2 = 0xffff, /* default */
322 .coex_pll_stabilization_time = 0xffffffff, /* default */
323 .ldo_stabilization_time = 0xffff, /* default */
324 .fm_disturbed_band_margin = 0xff, /* default */
325 .swallow_clk_diff = 0xff, /* default */
326 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300327 .rx_streaming = {
328 .duration = 150,
329 .queues = 0x1,
330 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300331 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300332 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300333 .fwlog = {
334 .mode = WL12XX_FWLOG_ON_DEMAND,
335 .mem_blocks = 2,
336 .severity = 0,
337 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
338 .output = WL12XX_FWLOG_OUTPUT_HOST,
339 .threshold = 0,
340 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300341 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300342 .rate = {
343 .rate_retry_score = 32000,
344 .per_add = 8192,
345 .per_th1 = 2048,
346 .per_th2 = 4096,
347 .max_per = 8100,
348 .inverse_curiosity_factor = 5,
349 .tx_fail_low_th = 4,
350 .tx_fail_high_th = 10,
351 .per_alpha_shift = 4,
352 .per_add_shift = 13,
353 .per_beta1_shift = 10,
354 .per_beta2_shift = 8,
355 .rate_check_up = 2,
356 .rate_check_down = 12,
357 .rate_retry_policy = {
358 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00,
361 },
362 },
Eliad Peller94877752011-08-28 15:11:56 +0300363 .hangover = {
364 .recover_time = 0,
365 .hangover_period = 20,
366 .dynamic_mode = 1,
367 .early_termination_mode = 1,
368 .max_period = 20,
369 .min_period = 1,
370 .increase_delta = 1,
371 .decrease_delta = 2,
372 .quiet_time = 4,
373 .increase_time = 1,
374 .window_size = 16,
375 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300376};
377
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300379static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300380
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300381static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200382 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300383 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200384static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200385static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200386
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200387static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300388static LIST_HEAD(wl_list);
389
Eliad Pellerba8447f2011-10-10 10:13:00 +0200390static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
391 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300392{
393 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200394
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300395 if (operstate != IF_OPER_UP)
396 return 0;
397
Eliad Peller8181aec2011-10-10 10:13:04 +0200398 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300399 return 0;
400
Eliad Peller154da672011-10-05 11:55:53 +0200401 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300402 if (ret < 0)
403 return ret;
404
Eliad Peller0603d892011-10-05 11:55:51 +0200405 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300406
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300407 wl1271_info("Association completed.");
408 return 0;
409}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300410static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
411 void *arg)
412{
413 struct net_device *dev = arg;
414 struct wireless_dev *wdev;
415 struct wiphy *wiphy;
416 struct ieee80211_hw *hw;
417 struct wl1271 *wl;
418 struct wl1271 *wl_temp;
Eliad Pellerba8447f2011-10-10 10:13:00 +0200419 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300420 int ret = 0;
421
422 /* Check that this notification is for us. */
423 if (what != NETDEV_CHANGE)
424 return NOTIFY_DONE;
425
426 wdev = dev->ieee80211_ptr;
427 if (wdev == NULL)
428 return NOTIFY_DONE;
429
430 wiphy = wdev->wiphy;
431 if (wiphy == NULL)
432 return NOTIFY_DONE;
433
434 hw = wiphy_priv(wiphy);
435 if (hw == NULL)
436 return NOTIFY_DONE;
437
438 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200439 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300440 list_for_each_entry(wl, &wl_list, list) {
441 if (wl == wl_temp)
442 break;
443 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200444 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300445 if (wl != wl_temp)
446 return NOTIFY_DONE;
447
448 mutex_lock(&wl->mutex);
449
450 if (wl->state == WL1271_STATE_OFF)
451 goto out;
452
Eliad Pellerba8447f2011-10-10 10:13:00 +0200453 wl12xx_for_each_wlvif_sta(wl, wlvif) {
454 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
455 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300456
Eliad Pellerba8447f2011-10-10 10:13:00 +0200457 ret = wl1271_ps_elp_wakeup(wl);
458 if (ret < 0)
459 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300460
Eliad Pellerba8447f2011-10-10 10:13:00 +0200461 wl1271_check_operstate(wl, wlvif, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300462
Eliad Pellerba8447f2011-10-10 10:13:00 +0200463 wl1271_ps_elp_sleep(wl);
464 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300465out:
466 mutex_unlock(&wl->mutex);
467
468 return NOTIFY_OK;
469}
470
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100471static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200472 struct regulatory_request *request)
473{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100474 struct ieee80211_supported_band *band;
475 struct ieee80211_channel *ch;
476 int i;
477
478 band = wiphy->bands[IEEE80211_BAND_5GHZ];
479 for (i = 0; i < band->n_channels; i++) {
480 ch = &band->channels[i];
481 if (ch->flags & IEEE80211_CHAN_DISABLED)
482 continue;
483
484 if (ch->flags & IEEE80211_CHAN_RADAR)
485 ch->flags |= IEEE80211_CHAN_NO_IBSS |
486 IEEE80211_CHAN_PASSIVE_SCAN;
487
488 }
489
490 return 0;
491}
492
Eliad Peller9eb599e2011-10-10 10:12:59 +0200493static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
494 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300495{
496 int ret = 0;
497
498 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200499 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300500 if (ret < 0)
501 goto out;
502
503 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200504 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300505 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200506 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300507out:
508 return ret;
509}
510
511/*
512 * this function is being called when the rx_streaming interval
513 * has beed changed or rx_streaming should be disabled
514 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200515int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300516{
517 int ret = 0;
518 int period = wl->conf.rx_streaming.interval;
519
520 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200521 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300522 goto out;
523
524 /* reconfigure/disable according to new streaming_period */
525 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200526 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300527 (wl->conf.rx_streaming.always ||
528 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200529 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300530 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200531 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300532 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200533 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300534 }
535out:
536 return ret;
537}
538
539static void wl1271_rx_streaming_enable_work(struct work_struct *work)
540{
541 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200542 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
543 rx_streaming_enable_work);
544 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300545
546 mutex_lock(&wl->mutex);
547
Eliad Peller0744bdb2011-10-10 10:13:05 +0200548 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200549 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300550 (!wl->conf.rx_streaming.always &&
551 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
552 goto out;
553
554 if (!wl->conf.rx_streaming.interval)
555 goto out;
556
557 ret = wl1271_ps_elp_wakeup(wl);
558 if (ret < 0)
559 goto out;
560
Eliad Peller9eb599e2011-10-10 10:12:59 +0200561 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300562 if (ret < 0)
563 goto out_sleep;
564
565 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200566 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300567 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
568
569out_sleep:
570 wl1271_ps_elp_sleep(wl);
571out:
572 mutex_unlock(&wl->mutex);
573}
574
575static void wl1271_rx_streaming_disable_work(struct work_struct *work)
576{
577 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200578 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
579 rx_streaming_disable_work);
580 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300581
582 mutex_lock(&wl->mutex);
583
Eliad Peller0744bdb2011-10-10 10:13:05 +0200584 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300585 goto out;
586
587 ret = wl1271_ps_elp_wakeup(wl);
588 if (ret < 0)
589 goto out;
590
Eliad Peller9eb599e2011-10-10 10:12:59 +0200591 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300592 if (ret)
593 goto out_sleep;
594
595out_sleep:
596 wl1271_ps_elp_sleep(wl);
597out:
598 mutex_unlock(&wl->mutex);
599}
600
601static void wl1271_rx_streaming_timer(unsigned long data)
602{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200603 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
604 struct wl1271 *wl = wlvif->wl;
605 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300606}
607
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300608static void wl1271_conf_init(struct wl1271 *wl)
609{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300610
611 /*
612 * This function applies the default configuration to the driver. This
613 * function is invoked upon driver load (spi probe.)
614 *
615 * The configuration is stored in a run-time structure in order to
616 * facilitate for run-time adjustment of any of the parameters. Making
617 * changes to the configuration structure will apply the new values on
618 * the next interface up (wl1271_op_start.)
619 */
620
621 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300622 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300623
Ido Yariv95dac04f2011-06-06 14:57:06 +0300624 /* Adjust settings according to optional module parameters */
625 if (fwlog_param) {
626 if (!strcmp(fwlog_param, "continuous")) {
627 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
628 } else if (!strcmp(fwlog_param, "ondemand")) {
629 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
630 } else if (!strcmp(fwlog_param, "dbgpins")) {
631 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
632 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
633 } else if (!strcmp(fwlog_param, "disable")) {
634 wl->conf.fwlog.mem_blocks = 0;
635 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
636 } else {
637 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
638 }
639 }
640}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300641
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300642static int wl1271_plt_init(struct wl1271 *wl)
643{
Eliad Peller188e7f52011-12-06 12:15:06 +0200644 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300645
Shahar Levi49d750ca2011-03-06 16:32:09 +0200646 if (wl->chip.id == CHIP_ID_1283_PG20)
647 ret = wl128x_cmd_general_parms(wl);
648 else
649 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200650 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200651 return ret;
652
Shahar Levi49d750ca2011-03-06 16:32:09 +0200653 if (wl->chip.id == CHIP_ID_1283_PG20)
654 ret = wl128x_cmd_radio_parms(wl);
655 else
656 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200657 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200658 return ret;
659
Shahar Levi49d750ca2011-03-06 16:32:09 +0200660 if (wl->chip.id != CHIP_ID_1283_PG20) {
661 ret = wl1271_cmd_ext_radio_parms(wl);
662 if (ret < 0)
663 return ret;
664 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200665 if (ret < 0)
666 return ret;
667
Shahar Levi48a61472011-03-06 16:32:08 +0200668 /* Chip-specific initializations */
669 ret = wl1271_chip_specific_init(wl);
670 if (ret < 0)
671 return ret;
672
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300673 ret = wl1271_acx_init_mem_config(wl);
674 if (ret < 0)
675 return ret;
676
Eliad Peller7f0979882011-08-14 13:17:06 +0300677 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600678 if (ret < 0)
679 goto out_free_memmap;
680
Luciano Coelho12419cc2010-02-18 13:25:44 +0200681 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200682 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200684 goto out_free_memmap;
685
686 /* Configure for CAM power saving (ie. always active) */
687 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
688 if (ret < 0)
689 goto out_free_memmap;
690
691 /* configure PM */
692 ret = wl1271_acx_pm_config(wl);
693 if (ret < 0)
694 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300695
696 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200697
698 out_free_memmap:
699 kfree(wl->target_mem_map);
700 wl->target_mem_map = NULL;
701
702 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300703}
704
Eliad Peller6e8cd332011-10-10 10:13:13 +0200705static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
706 struct wl12xx_vif *wlvif,
707 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200708{
Arik Nemtsovda032092011-08-25 12:43:15 +0300709 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200710
Arik Nemtsovb622d992011-02-23 00:22:31 +0200711 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300712 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200713
714 /*
715 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300716 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200717 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300718 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200719 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200720
Arik Nemtsovda032092011-08-25 12:43:15 +0300721 /*
722 * Start high-level PS if the STA is asleep with enough blocks in FW.
723 * Make an exception if this is the only connected station. In this
724 * case FW-memory congestion is not a problem.
725 */
726 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200727 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200728}
729
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300730static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200731 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300732 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200733{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200734 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200735 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300736 u8 hlid, cnt;
737
738 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200739
740 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
741 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
742 wl1271_debug(DEBUG_PSM,
743 "link ps prev 0x%x cur 0x%x changed 0x%x",
744 wl->ap_fw_ps_map, cur_fw_ps_map,
745 wl->ap_fw_ps_map ^ cur_fw_ps_map);
746
747 wl->ap_fw_ps_map = cur_fw_ps_map;
748 }
749
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200750 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
751 lnk = &wl->links[hlid];
752 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200753
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200754 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
755 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200756
Eliad Peller6e8cd332011-10-10 10:13:13 +0200757 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
758 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200759 }
760}
761
Eliad Peller4d56ad92011-08-14 13:17:05 +0300762static void wl12xx_fw_status(struct wl1271 *wl,
763 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300764{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200765 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200766 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200767 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300768 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300769 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300770
Eliad Peller4d56ad92011-08-14 13:17:05 +0300771 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200772
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300773 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
774 "drv_rx_counter = %d, tx_results_counter = %d)",
775 status->intr,
776 status->fw_rx_counter,
777 status->drv_rx_counter,
778 status->tx_results_counter);
779
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300780 for (i = 0; i < NUM_TX_QUEUES; i++) {
781 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300782 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300783 (status->tx_released_pkts[i] -
784 wl->tx_pkts_freed[i]) & 0xff;
785
786 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
787 }
788
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300789 /* prevent wrap-around in total blocks counter */
790 if (likely(wl->tx_blocks_freed <=
791 le32_to_cpu(status->total_released_blks)))
792 freed_blocks = le32_to_cpu(status->total_released_blks) -
793 wl->tx_blocks_freed;
794 else
795 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
796 le32_to_cpu(status->total_released_blks);
797
Eliad Peller4d56ad92011-08-14 13:17:05 +0300798 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200799
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300800 wl->tx_allocated_blocks -= freed_blocks;
801
Eliad Peller4d56ad92011-08-14 13:17:05 +0300802 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200803
Eliad Peller4d56ad92011-08-14 13:17:05 +0300804 /*
805 * The FW might change the total number of TX memblocks before
806 * we get a notification about blocks being released. Thus, the
807 * available blocks calculation might yield a temporary result
808 * which is lower than the actual available blocks. Keeping in
809 * mind that only blocks that were allocated can be moved from
810 * TX to RX, tx_blocks_available should never decrease here.
811 */
812 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
813 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300814
Ido Yariva5225502010-10-12 14:49:10 +0200815 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200816 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200817 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300818
Eliad Peller4d56ad92011-08-14 13:17:05 +0300819 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200820 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200821 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200822 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300823
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300824 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200825 getnstimeofday(&ts);
826 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
827 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828}
829
Ido Yariva6208652011-03-01 15:14:41 +0200830static void wl1271_flush_deferred_work(struct wl1271 *wl)
831{
832 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200833
Ido Yariva6208652011-03-01 15:14:41 +0200834 /* Pass all received frames to the network stack */
835 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
836 ieee80211_rx_ni(wl->hw, skb);
837
838 /* Return sent skbs to the network stack */
839 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300840 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200841}
842
843static void wl1271_netstack_work(struct work_struct *work)
844{
845 struct wl1271 *wl =
846 container_of(work, struct wl1271, netstack_work);
847
848 do {
849 wl1271_flush_deferred_work(wl);
850 } while (skb_queue_len(&wl->deferred_rx_queue));
851}
852
853#define WL1271_IRQ_MAX_LOOPS 256
854
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300855static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300856{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300857 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300858 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200859 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200860 struct wl1271 *wl = (struct wl1271 *)cookie;
861 bool done = false;
862 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200863 unsigned long flags;
864
865 /* TX might be handled here, avoid redundant work */
866 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
867 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300868
Ido Yariv341b7cd2011-03-31 10:07:01 +0200869 /*
870 * In case edge triggered interrupt must be used, we cannot iterate
871 * more than once without introducing race conditions with the hardirq.
872 */
873 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
874 loopcount = 1;
875
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300876 mutex_lock(&wl->mutex);
877
878 wl1271_debug(DEBUG_IRQ, "IRQ work");
879
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200880 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300881 goto out;
882
Ido Yariva6208652011-03-01 15:14:41 +0200883 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300884 if (ret < 0)
885 goto out;
886
Ido Yariva6208652011-03-01 15:14:41 +0200887 while (!done && loopcount--) {
888 /*
889 * In order to avoid a race with the hardirq, clear the flag
890 * before acknowledging the chip. Since the mutex is held,
891 * wl1271_ps_elp_wakeup cannot be called concurrently.
892 */
893 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
894 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200895
Eliad Peller4d56ad92011-08-14 13:17:05 +0300896 wl12xx_fw_status(wl, wl->fw_status);
897 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200898 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200899 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200900 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200901 continue;
902 }
903
Eliad Pellerccc83b02010-10-27 14:09:57 +0200904 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
905 wl1271_error("watchdog interrupt received! "
906 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300907 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200908
909 /* restarting the chip. ignore any other interrupt. */
910 goto out;
911 }
912
Ido Yariva6208652011-03-01 15:14:41 +0200913 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200914 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
915
Eliad Peller4d56ad92011-08-14 13:17:05 +0300916 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200917
Ido Yariva5225502010-10-12 14:49:10 +0200918 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200919 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200920 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300921 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200922 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200923 /*
924 * In order to avoid starvation of the TX path,
925 * call the work function directly.
926 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200927 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200928 } else {
929 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200930 }
931
Ido Yariv8aad2462011-03-01 15:14:38 +0200932 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300933 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200934 (wl->tx_results_count & 0xff))
935 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200936
937 /* Make sure the deferred queues don't get too long */
938 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
939 skb_queue_len(&wl->deferred_rx_queue);
940 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
941 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200942 }
943
944 if (intr & WL1271_ACX_INTR_EVENT_A) {
945 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
946 wl1271_event_handle(wl, 0);
947 }
948
949 if (intr & WL1271_ACX_INTR_EVENT_B) {
950 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
951 wl1271_event_handle(wl, 1);
952 }
953
954 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
955 wl1271_debug(DEBUG_IRQ,
956 "WL1271_ACX_INTR_INIT_COMPLETE");
957
958 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
959 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300960 }
961
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300962 wl1271_ps_elp_sleep(wl);
963
964out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200965 spin_lock_irqsave(&wl->wl_lock, flags);
966 /* In case TX was not handled here, queue TX work */
967 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
968 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300969 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200970 ieee80211_queue_work(wl->hw, &wl->tx_work);
971 spin_unlock_irqrestore(&wl->wl_lock, flags);
972
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300973 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200974
975 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300976}
977
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300978static int wl1271_fetch_firmware(struct wl1271 *wl)
979{
980 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200981 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300982 int ret;
983
Arik Nemtsovc302b2c2011-08-17 10:45:48 +0300984 if (wl->chip.id == CHIP_ID_1283_PG20)
985 fw_name = WL128X_FW_NAME;
986 else
987 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200988
989 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
990
Felipe Balbia390e852011-10-06 10:07:44 +0300991 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300992
993 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +0100994 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300995 return ret;
996 }
997
998 if (fw->size % 4) {
999 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1000 fw->size);
1001 ret = -EILSEQ;
1002 goto out;
1003 }
1004
Arik Nemtsov166d5042010-10-16 21:44:57 +02001005 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001006 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001007 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001008
1009 if (!wl->fw) {
1010 wl1271_error("could not allocate memory for the firmware");
1011 ret = -ENOMEM;
1012 goto out;
1013 }
1014
1015 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 ret = 0;
1017
1018out:
1019 release_firmware(fw);
1020
1021 return ret;
1022}
1023
1024static int wl1271_fetch_nvs(struct wl1271 *wl)
1025{
1026 const struct firmware *fw;
1027 int ret;
1028
Felipe Balbia390e852011-10-06 10:07:44 +03001029 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030
1031 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001032 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
1033 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034 return ret;
1035 }
1036
Shahar Levibc765bf2011-03-06 16:32:10 +02001037 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001038
1039 if (!wl->nvs) {
1040 wl1271_error("could not allocate memory for the nvs file");
1041 ret = -ENOMEM;
1042 goto out;
1043 }
1044
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001045 wl->nvs_len = fw->size;
1046
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047out:
1048 release_firmware(fw);
1049
1050 return ret;
1051}
1052
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001053void wl12xx_queue_recovery_work(struct wl1271 *wl)
1054{
1055 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1056 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1057}
1058
Ido Yariv95dac04f2011-06-06 14:57:06 +03001059size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1060{
1061 size_t len = 0;
1062
1063 /* The FW log is a length-value list, find where the log end */
1064 while (len < maxlen) {
1065 if (memblock[len] == 0)
1066 break;
1067 if (len + memblock[len] + 1 > maxlen)
1068 break;
1069 len += memblock[len] + 1;
1070 }
1071
1072 /* Make sure we have enough room */
1073 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1074
1075 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1076 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1077 wl->fwlog_size += len;
1078
1079 return len;
1080}
1081
1082static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1083{
1084 u32 addr;
1085 u32 first_addr;
1086 u8 *block;
1087
1088 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1089 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1090 (wl->conf.fwlog.mem_blocks == 0))
1091 return;
1092
1093 wl1271_info("Reading FW panic log");
1094
1095 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1096 if (!block)
1097 return;
1098
1099 /*
1100 * Make sure the chip is awake and the logger isn't active.
1101 * This might fail if the firmware hanged.
1102 */
1103 if (!wl1271_ps_elp_wakeup(wl))
1104 wl12xx_cmd_stop_fwlog(wl);
1105
1106 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001107 wl12xx_fw_status(wl, wl->fw_status);
1108 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001109 if (!first_addr)
1110 goto out;
1111
1112 /* Traverse the memory blocks linked list */
1113 addr = first_addr;
1114 do {
1115 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1116 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1117 false);
1118
1119 /*
1120 * Memory blocks are linked to one another. The first 4 bytes
1121 * of each memory block hold the hardware address of the next
1122 * one. The last memory block points to the first one.
1123 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001124 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001125 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1126 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1127 break;
1128 } while (addr && (addr != first_addr));
1129
1130 wake_up_interruptible(&wl->fwlog_waitq);
1131
1132out:
1133 kfree(block);
1134}
1135
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001136static void wl1271_recovery_work(struct work_struct *work)
1137{
1138 struct wl1271 *wl =
1139 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001140 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001141 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001142
1143 mutex_lock(&wl->mutex);
1144
1145 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001146 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001147
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001148 /* Avoid a recursive recovery */
1149 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1150
Ido Yariv95dac04f2011-06-06 14:57:06 +03001151 wl12xx_read_fwlog_panic(wl);
1152
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001153 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1154 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001155
Eliad Peller2a5bff02011-08-25 18:10:59 +03001156 BUG_ON(bug_on_recovery);
1157
Oz Krakowskib992c682011-06-26 10:36:02 +03001158 /*
1159 * Advance security sequence number to overcome potential progress
1160 * in the firmware during recovery. This doens't hurt if the network is
1161 * not encrypted.
1162 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001163 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001164 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001165 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001166 wlvif->tx_security_seq +=
1167 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1168 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001169
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001170 /* Prevent spurious TX during FW restart */
1171 ieee80211_stop_queues(wl->hw);
1172
Luciano Coelho33c2c062011-05-10 14:46:02 +03001173 if (wl->sched_scanning) {
1174 ieee80211_sched_scan_stopped(wl->hw);
1175 wl->sched_scanning = false;
1176 }
1177
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001178 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001179 while (!list_empty(&wl->wlvif_list)) {
1180 wlvif = list_first_entry(&wl->wlvif_list,
1181 struct wl12xx_vif, list);
1182 vif = wl12xx_wlvif_to_vif(wlvif);
1183 __wl1271_op_remove_interface(wl, vif, false);
1184 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001185 mutex_unlock(&wl->mutex);
1186 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001187
1188 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1189
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001190 ieee80211_restart_hw(wl->hw);
1191
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001192 /*
1193 * Its safe to enable TX now - the queues are stopped after a request
1194 * to restart the HW.
1195 */
1196 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001197 return;
1198out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001199 mutex_unlock(&wl->mutex);
1200}
1201
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001202static void wl1271_fw_wakeup(struct wl1271 *wl)
1203{
1204 u32 elp_reg;
1205
1206 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001207 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001208}
1209
1210static int wl1271_setup(struct wl1271 *wl)
1211{
1212 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1213 if (!wl->fw_status)
1214 return -ENOMEM;
1215
1216 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1217 if (!wl->tx_res_if) {
1218 kfree(wl->fw_status);
1219 return -ENOMEM;
1220 }
1221
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001222 return 0;
1223}
1224
1225static int wl1271_chip_wakeup(struct wl1271 *wl)
1226{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001227 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001228 int ret = 0;
1229
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001230 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001231 ret = wl1271_power_on(wl);
1232 if (ret < 0)
1233 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001234 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001235 wl1271_io_reset(wl);
1236 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001237
1238 /* We don't need a real memory partition here, because we only want
1239 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001240 memset(&partition, 0, sizeof(partition));
1241 partition.reg.start = REGISTERS_BASE;
1242 partition.reg.size = REGISTERS_DOWN_SIZE;
1243 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001244
1245 /* ELP module wake up */
1246 wl1271_fw_wakeup(wl);
1247
1248 /* whal_FwCtrl_BootSm() */
1249
1250 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001251 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001252
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001253 /*
1254 * For wl127x based devices we could use the default block
1255 * size (512 bytes), but due to a bug in the sdio driver, we
1256 * need to set it explicitly after the chip is powered on. To
1257 * simplify the code and since the performance impact is
1258 * negligible, we use the same block size for all different
1259 * chip types.
1260 */
1261 if (!wl1271_set_block_size(wl))
1262 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001263
1264 switch (wl->chip.id) {
1265 case CHIP_ID_1271_PG10:
1266 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1267 wl->chip.id);
1268
1269 ret = wl1271_setup(wl);
1270 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001271 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001272 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001274
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001275 case CHIP_ID_1271_PG20:
1276 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
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
Shahar Levi0830cee2011-03-06 16:32:20 +02001285 case CHIP_ID_1283_PG20:
1286 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1287 wl->chip.id);
1288
1289 ret = wl1271_setup(wl);
1290 if (ret < 0)
1291 goto out;
1292 break;
1293 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001295 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001297 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001298 }
1299
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001300 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301 ret = wl1271_fetch_firmware(wl);
1302 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001303 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001304 }
1305
1306 /* No NVS from netlink, try to get it from the filesystem */
1307 if (wl->nvs == NULL) {
1308 ret = wl1271_fetch_nvs(wl);
1309 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001310 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001311 }
1312
1313out:
1314 return ret;
1315}
1316
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001317int wl1271_plt_start(struct wl1271 *wl)
1318{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001319 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001320 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321 int ret;
1322
1323 mutex_lock(&wl->mutex);
1324
1325 wl1271_notice("power up");
1326
1327 if (wl->state != WL1271_STATE_OFF) {
1328 wl1271_error("cannot go into PLT state because not "
1329 "in off state: %d", wl->state);
1330 ret = -EBUSY;
1331 goto out;
1332 }
1333
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001334 while (retries) {
1335 retries--;
1336 ret = wl1271_chip_wakeup(wl);
1337 if (ret < 0)
1338 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001340 ret = wl1271_boot(wl);
1341 if (ret < 0)
1342 goto power_off;
1343
1344 ret = wl1271_plt_init(wl);
1345 if (ret < 0)
1346 goto irq_disable;
1347
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001348 wl->state = WL1271_STATE_PLT;
1349 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001350 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001351
Gery Kahn6f07b722011-07-18 14:21:49 +03001352 /* update hw/fw version info in wiphy struct */
1353 wiphy->hw_version = wl->chip.id;
1354 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1355 sizeof(wiphy->fw_version));
1356
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357 goto out;
1358
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001359irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001360 mutex_unlock(&wl->mutex);
1361 /* Unlocking the mutex in the middle of handling is
1362 inherently unsafe. In this case we deem it safe to do,
1363 because we need to let any possibly pending IRQ out of
1364 the system (and while we are WL1271_STATE_OFF the IRQ
1365 work function will not do anything.) Also, any other
1366 possible concurrent operations will fail due to the
1367 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001368 wl1271_disable_interrupts(wl);
1369 wl1271_flush_deferred_work(wl);
1370 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001371 mutex_lock(&wl->mutex);
1372power_off:
1373 wl1271_power_off(wl);
1374 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001375
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001376 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1377 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001378out:
1379 mutex_unlock(&wl->mutex);
1380
1381 return ret;
1382}
1383
Luciano Coelho4623ec72011-03-21 19:26:41 +02001384static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385{
1386 int ret = 0;
1387
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001388 wl1271_notice("power down");
1389
1390 if (wl->state != WL1271_STATE_PLT) {
1391 wl1271_error("cannot power down because not in PLT "
1392 "state: %d", wl->state);
1393 ret = -EBUSY;
1394 goto out;
1395 }
1396
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001397 wl1271_power_off(wl);
1398
1399 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001400 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001401
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001403 wl1271_disable_interrupts(wl);
1404 wl1271_flush_deferred_work(wl);
1405 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001406 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001407 mutex_lock(&wl->mutex);
1408out:
1409 return ret;
1410}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001411
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001412int wl1271_plt_stop(struct wl1271 *wl)
1413{
1414 int ret;
1415
1416 mutex_lock(&wl->mutex);
1417 ret = __wl1271_plt_stop(wl);
1418 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001419 return ret;
1420}
1421
Johannes Berg7bb45682011-02-24 14:42:06 +01001422static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001423{
1424 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001425 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1426 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001427 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001428 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001429 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001430 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001431
Eliad Peller0f168012011-10-11 13:52:25 +02001432 if (vif)
1433 wlvif = wl12xx_vif_to_data(vif);
1434
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001435 mapping = skb_get_queue_mapping(skb);
1436 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001437
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001438 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001439
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001440 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001441
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001442 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001443 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001444 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001445 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001446 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001447 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001448 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001449
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001450 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1451 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1452
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001453 wl->tx_queue_count[q]++;
1454
1455 /*
1456 * The workqueue is slow to process the tx_queue and we need stop
1457 * the queue here, otherwise the queue will get too long.
1458 */
1459 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1460 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1461 ieee80211_stop_queue(wl->hw, mapping);
1462 set_bit(q, &wl->stopped_queues_map);
1463 }
1464
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465 /*
1466 * The chip specific setup must run before the first TX packet -
1467 * before that, the tx_work will not be initialized!
1468 */
1469
Ido Yarivb07d4032011-03-01 15:14:43 +02001470 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1471 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001472 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001473
Arik Nemtsov04216da2011-08-14 13:17:38 +03001474out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001475 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001476}
1477
Shahar Leviae47c452011-03-06 16:32:14 +02001478int wl1271_tx_dummy_packet(struct wl1271 *wl)
1479{
Ido Yariv990f5de2011-03-31 10:06:59 +02001480 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001481 int q;
1482
1483 /* no need to queue a new dummy packet if one is already pending */
1484 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1485 return 0;
1486
1487 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001488
Ido Yariv990f5de2011-03-31 10:06:59 +02001489 spin_lock_irqsave(&wl->wl_lock, flags);
1490 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001491 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001492 spin_unlock_irqrestore(&wl->wl_lock, flags);
1493
1494 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1495 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001496 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001497
1498 /*
1499 * If the FW TX is busy, TX work will be scheduled by the threaded
1500 * interrupt handler function
1501 */
1502 return 0;
1503}
1504
1505/*
1506 * The size of the dummy packet should be at least 1400 bytes. However, in
1507 * order to minimize the number of bus transactions, aligning it to 512 bytes
1508 * boundaries could be beneficial, performance wise
1509 */
1510#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1511
Luciano Coelhocf27d862011-04-01 21:08:23 +03001512static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001513{
1514 struct sk_buff *skb;
1515 struct ieee80211_hdr_3addr *hdr;
1516 unsigned int dummy_packet_size;
1517
1518 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1519 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1520
1521 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001522 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001523 wl1271_warning("Failed to allocate a dummy packet skb");
1524 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001525 }
1526
1527 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1528
1529 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1530 memset(hdr, 0, sizeof(*hdr));
1531 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001532 IEEE80211_STYPE_NULLFUNC |
1533 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001534
Ido Yariv990f5de2011-03-31 10:06:59 +02001535 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001536
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001537 /* Dummy packets require the TID to be management */
1538 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001539
1540 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001541 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001542 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001543
Ido Yariv990f5de2011-03-31 10:06:59 +02001544 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001545}
1546
Ido Yariv990f5de2011-03-31 10:06:59 +02001547
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001548static struct notifier_block wl1271_dev_notifier = {
1549 .notifier_call = wl1271_dev_notify,
1550};
1551
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001552#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001553static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1554 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001555{
Eliad Pellere85d1622011-06-27 13:06:43 +03001556 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001557
Eliad Peller94390642011-05-13 11:57:13 +03001558 mutex_lock(&wl->mutex);
1559
Eliad Pellerba8447f2011-10-10 10:13:00 +02001560 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001561 goto out_unlock;
1562
Eliad Peller94390642011-05-13 11:57:13 +03001563 ret = wl1271_ps_elp_wakeup(wl);
1564 if (ret < 0)
1565 goto out_unlock;
1566
1567 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001568 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001569 DECLARE_COMPLETION_ONSTACK(compl);
1570
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001571 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001572 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001573 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001574 if (ret < 0)
1575 goto out_sleep;
1576
1577 /* we must unlock here so we will be able to get events */
1578 wl1271_ps_elp_sleep(wl);
1579 mutex_unlock(&wl->mutex);
1580
1581 ret = wait_for_completion_timeout(
1582 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
Pontus Fuchsef187062011-12-14 14:32:23 +01001583
1584 mutex_lock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001585 if (ret <= 0) {
1586 wl1271_warning("couldn't enter ps mode!");
1587 ret = -EBUSY;
Pontus Fuchsef187062011-12-14 14:32:23 +01001588 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001589 }
1590
Eliad Peller94390642011-05-13 11:57:13 +03001591 ret = wl1271_ps_elp_wakeup(wl);
1592 if (ret < 0)
Pontus Fuchsef187062011-12-14 14:32:23 +01001593 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001594 }
1595out_sleep:
1596 wl1271_ps_elp_sleep(wl);
Pontus Fuchsef187062011-12-14 14:32:23 +01001597out_cleanup:
1598 wlvif->ps_compl = NULL;
Eliad Peller94390642011-05-13 11:57:13 +03001599out_unlock:
1600 mutex_unlock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001601 return ret;
1602
1603}
1604
Eliad Peller0603d892011-10-05 11:55:51 +02001605static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1606 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001607{
Eliad Pellere85d1622011-06-27 13:06:43 +03001608 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001609
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001610 mutex_lock(&wl->mutex);
1611
Eliad Peller53d40d02011-10-10 10:13:02 +02001612 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001613 goto out_unlock;
1614
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001615 ret = wl1271_ps_elp_wakeup(wl);
1616 if (ret < 0)
1617 goto out_unlock;
1618
Eliad Peller0603d892011-10-05 11:55:51 +02001619 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001620
1621 wl1271_ps_elp_sleep(wl);
1622out_unlock:
1623 mutex_unlock(&wl->mutex);
1624 return ret;
1625
1626}
1627
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001628static int wl1271_configure_suspend(struct wl1271 *wl,
1629 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001630{
Eliad Peller536129c2011-10-05 11:55:45 +02001631 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001632 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001633 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001634 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001635 return 0;
1636}
1637
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001638static void wl1271_configure_resume(struct wl1271 *wl,
1639 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001640{
1641 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001642 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1643 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001644
1645 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001646 return;
1647
1648 mutex_lock(&wl->mutex);
1649 ret = wl1271_ps_elp_wakeup(wl);
1650 if (ret < 0)
1651 goto out;
1652
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001653 if (is_sta) {
1654 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001655 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001656 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001657 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001658 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001659 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001660 }
Eliad Peller94390642011-05-13 11:57:13 +03001661
1662 wl1271_ps_elp_sleep(wl);
1663out:
1664 mutex_unlock(&wl->mutex);
1665}
1666
Eliad Peller402e48612011-05-13 11:57:09 +03001667static int wl1271_op_suspend(struct ieee80211_hw *hw,
1668 struct cfg80211_wowlan *wow)
1669{
1670 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001671 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001672 int ret;
1673
Eliad Peller402e48612011-05-13 11:57:09 +03001674 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001675 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001676
Eliad Peller4a859df2011-06-06 12:21:52 +03001677 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001678 wl12xx_for_each_wlvif(wl, wlvif) {
1679 ret = wl1271_configure_suspend(wl, wlvif);
1680 if (ret < 0) {
1681 wl1271_warning("couldn't prepare device to suspend");
1682 return ret;
1683 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001684 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001685 /* flush any remaining work */
1686 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001687
1688 /*
1689 * disable and re-enable interrupts in order to flush
1690 * the threaded_irq
1691 */
1692 wl1271_disable_interrupts(wl);
1693
1694 /*
1695 * set suspended flag to avoid triggering a new threaded_irq
1696 * work. no need for spinlock as interrupts are disabled.
1697 */
1698 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1699
1700 wl1271_enable_interrupts(wl);
1701 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001702 wl12xx_for_each_wlvif(wl, wlvif) {
1703 flush_delayed_work(&wlvif->pspoll_work);
1704 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001705 flush_delayed_work(&wl->elp_work);
1706
Eliad Peller402e48612011-05-13 11:57:09 +03001707 return 0;
1708}
1709
1710static int wl1271_op_resume(struct ieee80211_hw *hw)
1711{
1712 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001713 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001714 unsigned long flags;
1715 bool run_irq_work = false;
1716
Eliad Peller402e48612011-05-13 11:57:09 +03001717 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1718 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001719 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001720
1721 /*
1722 * re-enable irq_work enqueuing, and call irq_work directly if
1723 * there is a pending work.
1724 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001725 spin_lock_irqsave(&wl->wl_lock, flags);
1726 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1727 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1728 run_irq_work = true;
1729 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001730
Eliad Peller4a859df2011-06-06 12:21:52 +03001731 if (run_irq_work) {
1732 wl1271_debug(DEBUG_MAC80211,
1733 "run postponed irq_work directly");
1734 wl1271_irq(0, wl);
1735 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001736 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001737 wl12xx_for_each_wlvif(wl, wlvif) {
1738 wl1271_configure_resume(wl, wlvif);
1739 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001740 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001741
Eliad Peller402e48612011-05-13 11:57:09 +03001742 return 0;
1743}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001744#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001745
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001746static int wl1271_op_start(struct ieee80211_hw *hw)
1747{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001748 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1749
1750 /*
1751 * We have to delay the booting of the hardware because
1752 * we need to know the local MAC address before downloading and
1753 * initializing the firmware. The MAC address cannot be changed
1754 * after boot, and without the proper MAC address, the firmware
1755 * will not function properly.
1756 *
1757 * The MAC address is first known when the corresponding interface
1758 * is added. That is where we will initialize the hardware.
1759 */
1760
1761 return 0;
1762}
1763
1764static void wl1271_op_stop(struct ieee80211_hw *hw)
1765{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001766 struct wl1271 *wl = hw->priv;
1767 int i;
1768
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001769 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001770
Eliad Peller10c8cd02011-10-10 10:13:06 +02001771 mutex_lock(&wl->mutex);
1772 if (wl->state == WL1271_STATE_OFF) {
1773 mutex_unlock(&wl->mutex);
1774 return;
1775 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001776 /*
1777 * this must be before the cancel_work calls below, so that the work
1778 * functions don't perform further work.
1779 */
1780 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001781 mutex_unlock(&wl->mutex);
1782
1783 mutex_lock(&wl_list_mutex);
1784 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001785 mutex_unlock(&wl_list_mutex);
1786
1787 wl1271_disable_interrupts(wl);
1788 wl1271_flush_deferred_work(wl);
1789 cancel_delayed_work_sync(&wl->scan_complete_work);
1790 cancel_work_sync(&wl->netstack_work);
1791 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001792 cancel_delayed_work_sync(&wl->elp_work);
1793
1794 /* let's notify MAC80211 about the remaining pending TX frames */
1795 wl12xx_tx_reset(wl, true);
1796 mutex_lock(&wl->mutex);
1797
1798 wl1271_power_off(wl);
1799
1800 wl->band = IEEE80211_BAND_2GHZ;
1801
1802 wl->rx_counter = 0;
1803 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1804 wl->tx_blocks_available = 0;
1805 wl->tx_allocated_blocks = 0;
1806 wl->tx_results_count = 0;
1807 wl->tx_packets_count = 0;
1808 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001809 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1810 wl->ap_fw_ps_map = 0;
1811 wl->ap_ps_map = 0;
1812 wl->sched_scanning = false;
1813 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1814 memset(wl->links_map, 0, sizeof(wl->links_map));
1815 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1816 wl->active_sta_count = 0;
1817
1818 /* The system link is always allocated */
1819 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1820
1821 /*
1822 * this is performed after the cancel_work calls and the associated
1823 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1824 * get executed before all these vars have been reset.
1825 */
1826 wl->flags = 0;
1827
1828 wl->tx_blocks_freed = 0;
1829
1830 for (i = 0; i < NUM_TX_QUEUES; i++) {
1831 wl->tx_pkts_freed[i] = 0;
1832 wl->tx_allocated_pkts[i] = 0;
1833 }
1834
1835 wl1271_debugfs_reset(wl);
1836
1837 kfree(wl->fw_status);
1838 wl->fw_status = NULL;
1839 kfree(wl->tx_res_if);
1840 wl->tx_res_if = NULL;
1841 kfree(wl->target_mem_map);
1842 wl->target_mem_map = NULL;
1843
1844 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001845}
1846
Eliad Pellere5a359f2011-10-10 10:13:15 +02001847static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1848{
1849 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1850 WL12XX_MAX_RATE_POLICIES);
1851 if (policy >= WL12XX_MAX_RATE_POLICIES)
1852 return -EBUSY;
1853
1854 __set_bit(policy, wl->rate_policies_map);
1855 *idx = policy;
1856 return 0;
1857}
1858
1859static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1860{
1861 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1862 return;
1863
1864 __clear_bit(*idx, wl->rate_policies_map);
1865 *idx = WL12XX_MAX_RATE_POLICIES;
1866}
1867
Eliad Peller536129c2011-10-05 11:55:45 +02001868static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001869{
Eliad Peller536129c2011-10-05 11:55:45 +02001870 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001871 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001872 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001873 return WL1271_ROLE_P2P_GO;
1874 else
1875 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001876
1877 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001878 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001879 return WL1271_ROLE_P2P_CL;
1880 else
1881 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001882
Eliad Peller227e81e2011-08-14 13:17:26 +03001883 case BSS_TYPE_IBSS:
1884 return WL1271_ROLE_IBSS;
1885
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001886 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001887 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001888 }
1889 return WL12XX_INVALID_ROLE_TYPE;
1890}
1891
Eliad Peller83587502011-10-10 10:12:53 +02001892static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001893{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001894 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001895 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001896
Eliad Peller48e93e42011-10-10 10:12:58 +02001897 /* clear everything but the persistent data */
1898 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001899
1900 switch (ieee80211_vif_type_p2p(vif)) {
1901 case NL80211_IFTYPE_P2P_CLIENT:
1902 wlvif->p2p = 1;
1903 /* fall-through */
1904 case NL80211_IFTYPE_STATION:
1905 wlvif->bss_type = BSS_TYPE_STA_BSS;
1906 break;
1907 case NL80211_IFTYPE_ADHOC:
1908 wlvif->bss_type = BSS_TYPE_IBSS;
1909 break;
1910 case NL80211_IFTYPE_P2P_GO:
1911 wlvif->p2p = 1;
1912 /* fall-through */
1913 case NL80211_IFTYPE_AP:
1914 wlvif->bss_type = BSS_TYPE_AP_BSS;
1915 break;
1916 default:
1917 wlvif->bss_type = MAX_BSS_TYPE;
1918 return -EOPNOTSUPP;
1919 }
1920
Eliad Peller0603d892011-10-05 11:55:51 +02001921 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001922 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001923 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001924
Eliad Pellere936bbe2011-10-05 11:55:56 +02001925 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1926 wlvif->bss_type == BSS_TYPE_IBSS) {
1927 /* init sta/ibss data */
1928 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001929 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1930 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1931 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001932 } else {
1933 /* init ap data */
1934 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1935 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001936 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1937 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1938 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1939 wl12xx_allocate_rate_policy(wl,
1940 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001941 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001942
Eliad Peller83587502011-10-10 10:12:53 +02001943 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1944 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001945 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001946 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001947 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001948 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1949
Eliad Peller1b92f152011-10-10 10:13:09 +02001950 /*
1951 * mac80211 configures some values globally, while we treat them
1952 * per-interface. thus, on init, we have to copy them from wl
1953 */
1954 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001955 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001956 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02001957
Eliad Peller9eb599e2011-10-10 10:12:59 +02001958 INIT_WORK(&wlvif->rx_streaming_enable_work,
1959 wl1271_rx_streaming_enable_work);
1960 INIT_WORK(&wlvif->rx_streaming_disable_work,
1961 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02001962 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02001963 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001964
Eliad Peller9eb599e2011-10-10 10:12:59 +02001965 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1966 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001967 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001968}
1969
Eliad Peller1d095472011-10-10 10:12:49 +02001970static bool wl12xx_init_fw(struct wl1271 *wl)
1971{
1972 int retries = WL1271_BOOT_RETRIES;
1973 bool booted = false;
1974 struct wiphy *wiphy = wl->hw->wiphy;
1975 int ret;
1976
1977 while (retries) {
1978 retries--;
1979 ret = wl1271_chip_wakeup(wl);
1980 if (ret < 0)
1981 goto power_off;
1982
1983 ret = wl1271_boot(wl);
1984 if (ret < 0)
1985 goto power_off;
1986
1987 ret = wl1271_hw_init(wl);
1988 if (ret < 0)
1989 goto irq_disable;
1990
1991 booted = true;
1992 break;
1993
1994irq_disable:
1995 mutex_unlock(&wl->mutex);
1996 /* Unlocking the mutex in the middle of handling is
1997 inherently unsafe. In this case we deem it safe to do,
1998 because we need to let any possibly pending IRQ out of
1999 the system (and while we are WL1271_STATE_OFF the IRQ
2000 work function will not do anything.) Also, any other
2001 possible concurrent operations will fail due to the
2002 current state, hence the wl1271 struct should be safe. */
2003 wl1271_disable_interrupts(wl);
2004 wl1271_flush_deferred_work(wl);
2005 cancel_work_sync(&wl->netstack_work);
2006 mutex_lock(&wl->mutex);
2007power_off:
2008 wl1271_power_off(wl);
2009 }
2010
2011 if (!booted) {
2012 wl1271_error("firmware boot failed despite %d retries",
2013 WL1271_BOOT_RETRIES);
2014 goto out;
2015 }
2016
2017 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2018
2019 /* update hw/fw version info in wiphy struct */
2020 wiphy->hw_version = wl->chip.id;
2021 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2022 sizeof(wiphy->fw_version));
2023
2024 /*
2025 * Now we know if 11a is supported (info from the NVS), so disable
2026 * 11a channels if not supported
2027 */
2028 if (!wl->enable_11a)
2029 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2030
2031 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2032 wl->enable_11a ? "" : "not ");
2033
2034 wl->state = WL1271_STATE_ON;
2035out:
2036 return booted;
2037}
2038
Eliad Peller92e712d2011-12-18 20:25:43 +02002039static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2040{
2041 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2042}
2043
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002044static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2045 struct ieee80211_vif *vif)
2046{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002047 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002048 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002049 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002050 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002051 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002053 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002054 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002055
2056 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002057 ret = wl1271_ps_elp_wakeup(wl);
2058 if (ret < 0)
2059 goto out_unlock;
2060
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002061 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002062 wl1271_debug(DEBUG_MAC80211,
2063 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002064 ret = -EBUSY;
2065 goto out;
2066 }
2067
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002068 /*
2069 * in some very corner case HW recovery scenarios its possible to
2070 * get here before __wl1271_op_remove_interface is complete, so
2071 * opt out if that is the case.
2072 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002073 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2074 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002075 ret = -EBUSY;
2076 goto out;
2077 }
2078
Eliad Peller83587502011-10-10 10:12:53 +02002079 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002080 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002081 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002082
Eliad Peller252efa42011-10-05 11:56:00 +02002083 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002084 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002085 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2086 ret = -EINVAL;
2087 goto out;
2088 }
Eliad Peller1d095472011-10-10 10:12:49 +02002089
Eliad Peller784f6942011-10-05 11:55:39 +02002090 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002091 * TODO: after the nvs issue will be solved, move this block
2092 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002093 */
Eliad Peller1d095472011-10-10 10:12:49 +02002094 if (wl->state == WL1271_STATE_OFF) {
2095 /*
2096 * we still need this in order to configure the fw
2097 * while uploading the nvs
2098 */
2099 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002100
Eliad Peller1d095472011-10-10 10:12:49 +02002101 booted = wl12xx_init_fw(wl);
2102 if (!booted) {
2103 ret = -EINVAL;
2104 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002105 }
Eliad Peller1d095472011-10-10 10:12:49 +02002106 }
Eliad Peller04e80792011-08-14 13:17:09 +03002107
Eliad Peller1d095472011-10-10 10:12:49 +02002108 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2109 wlvif->bss_type == BSS_TYPE_IBSS) {
2110 /*
2111 * The device role is a special role used for
2112 * rx and tx frames prior to association (as
2113 * the STA role can get packets only from
2114 * its associated bssid)
2115 */
Eliad Peller784f6942011-10-05 11:55:39 +02002116 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002117 WL1271_ROLE_DEVICE,
2118 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002119 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002120 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002121 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002122
Eliad Peller1d095472011-10-10 10:12:49 +02002123 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2124 role_type, &wlvif->role_id);
2125 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002126 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002127
2128 ret = wl1271_init_vif_specific(wl, vif);
2129 if (ret < 0)
2130 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002131
2132 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002133 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002134 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002135
2136 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2137 wl->ap_count++;
2138 else
2139 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002140out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002141 wl1271_ps_elp_sleep(wl);
2142out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002143 mutex_unlock(&wl->mutex);
2144
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002145 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002146 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002147 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002148 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002149
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002150 return ret;
2151}
2152
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002153static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002154 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002155 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002156{
Eliad Peller536129c2011-10-05 11:55:45 +02002157 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002158 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002159
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002160 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002161
Eliad Peller10c8cd02011-10-10 10:13:06 +02002162 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2163 return;
2164
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002165 wl->vif = NULL;
2166
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002167 /* because of hardware recovery, we may get here twice */
2168 if (wl->state != WL1271_STATE_ON)
2169 return;
2170
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002171 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002172
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002173 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002174 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002175 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002176
Eliad Pellerbaf62772011-10-10 10:12:52 +02002177 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2178 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002179 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002180 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002181 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002182 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002183 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002184 }
2185
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002186 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2187 /* disable active roles */
2188 ret = wl1271_ps_elp_wakeup(wl);
2189 if (ret < 0)
2190 goto deinit;
2191
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002192 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2193 wlvif->bss_type == BSS_TYPE_IBSS) {
2194 if (wl12xx_dev_role_started(wlvif))
2195 wl12xx_stop_dev(wl, wlvif);
2196
Eliad Peller7edebf52011-10-05 11:55:52 +02002197 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002198 if (ret < 0)
2199 goto deinit;
2200 }
2201
Eliad Peller0603d892011-10-05 11:55:51 +02002202 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002203 if (ret < 0)
2204 goto deinit;
2205
2206 wl1271_ps_elp_sleep(wl);
2207 }
2208deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002209 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002210 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002211
2212 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2213 wlvif->bss_type == BSS_TYPE_IBSS) {
2214 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2215 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2216 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2217 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2218 } else {
2219 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2220 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2221 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2222 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2223 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2224 wl12xx_free_rate_policy(wl,
2225 &wlvif->ap.ucast_rate_idx[i]);
2226 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002227
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002228 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002229 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002230 if (wl->last_wlvif == wlvif)
2231 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002232 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002233 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002234 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002235 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002236
Eliad Pellera4e41302011-10-11 11:49:15 +02002237 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2238 wl->ap_count--;
2239 else
2240 wl->sta_count--;
2241
Eliad Pellerbaf62772011-10-10 10:12:52 +02002242 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002243 del_timer_sync(&wlvif->rx_streaming_timer);
2244 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2245 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002246 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002247
Eliad Pellerbaf62772011-10-10 10:12:52 +02002248 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002249}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002250
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002251static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2252 struct ieee80211_vif *vif)
2253{
2254 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002255 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002256 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002257
2258 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002259
2260 if (wl->state == WL1271_STATE_OFF ||
2261 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2262 goto out;
2263
Juuso Oikarinen67353292010-11-18 15:19:02 +02002264 /*
2265 * wl->vif can be null here if someone shuts down the interface
2266 * just when hardware recovery has been started.
2267 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002268 wl12xx_for_each_wlvif(wl, iter) {
2269 if (iter != wlvif)
2270 continue;
2271
Eliad Peller536129c2011-10-05 11:55:45 +02002272 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002273 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002274 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002275 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002276out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002277 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002278 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002279}
2280
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002281static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2282 struct ieee80211_vif *vif,
2283 enum nl80211_iftype new_type, bool p2p)
2284{
2285 wl1271_op_remove_interface(hw, vif);
2286
2287 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2288 vif->p2p = p2p;
2289 return wl1271_op_add_interface(hw, vif);
2290}
2291
Eliad Peller87fbcb02011-10-05 11:55:41 +02002292static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2293 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002294{
2295 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002296 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002297
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002298 /*
2299 * One of the side effects of the JOIN command is that is clears
2300 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2301 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002302 * Currently the only valid scenario for JOIN during association
2303 * is on roaming, in which case we will also be given new keys.
2304 * Keep the below message for now, unless it starts bothering
2305 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002306 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002307 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002308 wl1271_info("JOIN while associated.");
2309
2310 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002311 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002312
Eliad Peller227e81e2011-08-14 13:17:26 +03002313 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002314 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002315 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002316 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002317 if (ret < 0)
2318 goto out;
2319
Eliad Pellerba8447f2011-10-10 10:13:00 +02002320 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002321 goto out;
2322
2323 /*
2324 * The join command disable the keep-alive mode, shut down its process,
2325 * and also clear the template config, so we need to reset it all after
2326 * the join. The acx_aid starts the keep-alive process, and the order
2327 * of the commands below is relevant.
2328 */
Eliad Peller0603d892011-10-05 11:55:51 +02002329 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002330 if (ret < 0)
2331 goto out;
2332
Eliad Peller0603d892011-10-05 11:55:51 +02002333 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002334 if (ret < 0)
2335 goto out;
2336
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002337 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002338 if (ret < 0)
2339 goto out;
2340
Eliad Peller0603d892011-10-05 11:55:51 +02002341 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2342 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002343 ACX_KEEP_ALIVE_TPL_VALID);
2344 if (ret < 0)
2345 goto out;
2346
2347out:
2348 return ret;
2349}
2350
Eliad Peller0603d892011-10-05 11:55:51 +02002351static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002352{
2353 int ret;
2354
Eliad Peller52630c52011-10-10 10:13:08 +02002355 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002356 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2357
Shahar Levi6d158ff2011-09-08 13:01:33 +03002358 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002359 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002360 }
2361
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002362 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002363 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002364 if (ret < 0)
2365 goto out;
2366
Oz Krakowskib992c682011-06-26 10:36:02 +03002367 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002368 wlvif->tx_security_last_seq_lsb = 0;
2369 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002370
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002371out:
2372 return ret;
2373}
2374
Eliad Peller87fbcb02011-10-05 11:55:41 +02002375static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002376{
Eliad Peller1b92f152011-10-10 10:13:09 +02002377 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002378 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002379}
2380
Eliad Peller87fbcb02011-10-05 11:55:41 +02002381static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2382 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002383{
2384 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002385 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2386
2387 if (idle == cur_idle)
2388 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002389
2390 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002391 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002392 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002393 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002394 if (ret < 0)
2395 goto out;
2396 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002397 wlvif->rate_set =
2398 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2399 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002400 if (ret < 0)
2401 goto out;
2402 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002403 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002404 ACX_KEEP_ALIVE_TPL_INVALID);
2405 if (ret < 0)
2406 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002407 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002408 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002409 /* The current firmware only supports sched_scan in idle */
2410 if (wl->sched_scanning) {
2411 wl1271_scan_sched_scan_stop(wl);
2412 ieee80211_sched_scan_stopped(wl->hw);
2413 }
2414
Eliad Peller679a6732011-10-11 11:55:44 +02002415 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002416 if (ret < 0)
2417 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002418 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002419 }
2420
2421out:
2422 return ret;
2423}
2424
Eliad Peller9f259c42011-10-10 10:13:12 +02002425static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2426 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002427{
Eliad Peller9f259c42011-10-10 10:13:12 +02002428 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2429 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002430
2431 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2432
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002433 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002434 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002435 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002436 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002437 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002438 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002439 wlvif->band = conf->channel->band;
2440 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002441
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002442 if (!is_ap) {
2443 /*
2444 * FIXME: the mac80211 should really provide a fixed
2445 * rate to use here. for now, just use the smallest
2446 * possible rate for the band as a fixed rate for
2447 * association frames and other control messages.
2448 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002449 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002450 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002451
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002452 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002453 wl1271_tx_min_rate_get(wl,
2454 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002455 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002456 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002457 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002458 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002459
Eliad Pellerba8447f2011-10-10 10:13:00 +02002460 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2461 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002462 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002463 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002464 ret = wl12xx_croc(wl,
2465 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002466 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002467 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002468 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002469 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002470 if (ret < 0)
2471 wl1271_warning("cmd join on channel "
2472 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002473 } else {
2474 /*
2475 * change the ROC channel. do it only if we are
2476 * not idle. otherwise, CROC will be called
2477 * anyway.
2478 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002479 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002480 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002481 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002482 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002483 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002484
Eliad Peller679a6732011-10-11 11:55:44 +02002485 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002486 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002487 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002488 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002489 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002490 }
2491 }
2492
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002493 /*
2494 * if mac80211 changes the PSM mode, make sure the mode is not
2495 * incorrectly changed after the pspoll failure active window.
2496 */
2497 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002498 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002499
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002500 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002501 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2502 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002503
2504 /*
2505 * We enter PSM only if we're already associated.
2506 * If we're not, we'll enter it when joining an SSID,
2507 * through the bss_info_changed() hook.
2508 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002509 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002510 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002511 ret = wl1271_ps_set_mode(wl, wlvif,
2512 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002513 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002514 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002515 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002516 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002517 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002518
Eliad Pellerc29bb002011-10-10 10:13:03 +02002519 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002520
Eliad Pellerc29bb002011-10-10 10:13:03 +02002521 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002522 ret = wl1271_ps_set_mode(wl, wlvif,
2523 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002524 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002525 }
2526
Eliad Peller6bd65022011-10-10 10:13:11 +02002527 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002528 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002529 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002530 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002531
Eliad Peller6bd65022011-10-10 10:13:11 +02002532 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002533 }
2534
Eliad Peller9f259c42011-10-10 10:13:12 +02002535 return 0;
2536}
2537
2538static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2539{
2540 struct wl1271 *wl = hw->priv;
2541 struct wl12xx_vif *wlvif;
2542 struct ieee80211_conf *conf = &hw->conf;
2543 int channel, ret = 0;
2544
2545 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2546
2547 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2548 " changed 0x%x",
2549 channel,
2550 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2551 conf->power_level,
2552 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2553 changed);
2554
2555 /*
2556 * mac80211 will go to idle nearly immediately after transmitting some
2557 * frames, such as the deauth. To make sure those frames reach the air,
2558 * wait here until the TX queue is fully flushed.
2559 */
2560 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2561 (conf->flags & IEEE80211_CONF_IDLE))
2562 wl1271_tx_flush(wl);
2563
2564 mutex_lock(&wl->mutex);
2565
2566 /* we support configuring the channel and band even while off */
2567 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2568 wl->band = conf->channel->band;
2569 wl->channel = channel;
2570 }
2571
2572 if (changed & IEEE80211_CONF_CHANGE_POWER)
2573 wl->power_level = conf->power_level;
2574
2575 if (unlikely(wl->state == WL1271_STATE_OFF))
2576 goto out;
2577
2578 ret = wl1271_ps_elp_wakeup(wl);
2579 if (ret < 0)
2580 goto out;
2581
2582 /* configure each interface */
2583 wl12xx_for_each_wlvif(wl, wlvif) {
2584 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2585 if (ret < 0)
2586 goto out_sleep;
2587 }
2588
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002589out_sleep:
2590 wl1271_ps_elp_sleep(wl);
2591
2592out:
2593 mutex_unlock(&wl->mutex);
2594
2595 return ret;
2596}
2597
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002598struct wl1271_filter_params {
2599 bool enabled;
2600 int mc_list_length;
2601 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2602};
2603
Jiri Pirko22bedad2010-04-01 21:22:57 +00002604static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2605 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002606{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002607 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002608 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002609 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002610
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002611 if (unlikely(wl->state == WL1271_STATE_OFF))
2612 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002613
Juuso Oikarinen74441132009-10-13 12:47:53 +03002614 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002615 if (!fp) {
2616 wl1271_error("Out of memory setting filters.");
2617 return 0;
2618 }
2619
2620 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002621 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002622 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2623 fp->enabled = false;
2624 } else {
2625 fp->enabled = true;
2626 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002627 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002628 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002629 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002630 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002631 }
2632
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002633 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002634}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002635
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002636#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2637 FIF_ALLMULTI | \
2638 FIF_FCSFAIL | \
2639 FIF_BCN_PRBRESP_PROMISC | \
2640 FIF_CONTROL | \
2641 FIF_OTHER_BSS)
2642
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002643static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2644 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002645 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002646{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002647 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002648 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002649 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002650
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002651 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002652
Arik Nemtsov7d057862010-10-16 19:25:35 +02002653 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2654 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002655
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002656 mutex_lock(&wl->mutex);
2657
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002658 *total &= WL1271_SUPPORTED_FILTERS;
2659 changed &= WL1271_SUPPORTED_FILTERS;
2660
2661 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002662 goto out;
2663
Ido Yariva6208652011-03-01 15:14:41 +02002664 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002665 if (ret < 0)
2666 goto out;
2667
Eliad Peller6e8cd332011-10-10 10:13:13 +02002668 wl12xx_for_each_wlvif(wl, wlvif) {
2669 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2670 if (*total & FIF_ALLMULTI)
2671 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2672 false,
2673 NULL, 0);
2674 else if (fp)
2675 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2676 fp->enabled,
2677 fp->mc_list,
2678 fp->mc_list_length);
2679 if (ret < 0)
2680 goto out_sleep;
2681 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002682 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002683
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002684 /*
2685 * the fw doesn't provide an api to configure the filters. instead,
2686 * the filters configuration is based on the active roles / ROC
2687 * state.
2688 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002689
2690out_sleep:
2691 wl1271_ps_elp_sleep(wl);
2692
2693out:
2694 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002695 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002696}
2697
Eliad Peller170d0e62011-10-05 11:56:06 +02002698static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2699 u8 id, u8 key_type, u8 key_size,
2700 const u8 *key, u8 hlid, u32 tx_seq_32,
2701 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002702{
2703 struct wl1271_ap_key *ap_key;
2704 int i;
2705
2706 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2707
2708 if (key_size > MAX_KEY_SIZE)
2709 return -EINVAL;
2710
2711 /*
2712 * Find next free entry in ap_keys. Also check we are not replacing
2713 * an existing key.
2714 */
2715 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002716 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002717 break;
2718
Eliad Peller170d0e62011-10-05 11:56:06 +02002719 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002720 wl1271_warning("trying to record key replacement");
2721 return -EINVAL;
2722 }
2723 }
2724
2725 if (i == MAX_NUM_KEYS)
2726 return -EBUSY;
2727
2728 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2729 if (!ap_key)
2730 return -ENOMEM;
2731
2732 ap_key->id = id;
2733 ap_key->key_type = key_type;
2734 ap_key->key_size = key_size;
2735 memcpy(ap_key->key, key, key_size);
2736 ap_key->hlid = hlid;
2737 ap_key->tx_seq_32 = tx_seq_32;
2738 ap_key->tx_seq_16 = tx_seq_16;
2739
Eliad Peller170d0e62011-10-05 11:56:06 +02002740 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002741 return 0;
2742}
2743
Eliad Peller170d0e62011-10-05 11:56:06 +02002744static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002745{
2746 int i;
2747
2748 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002749 kfree(wlvif->ap.recorded_keys[i]);
2750 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002751 }
2752}
2753
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002754static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002755{
2756 int i, ret = 0;
2757 struct wl1271_ap_key *key;
2758 bool wep_key_added = false;
2759
2760 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002761 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002762 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002763 break;
2764
Eliad Peller170d0e62011-10-05 11:56:06 +02002765 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002766 hlid = key->hlid;
2767 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002768 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002769
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002770 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002771 key->id, key->key_type,
2772 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002773 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002774 key->tx_seq_16);
2775 if (ret < 0)
2776 goto out;
2777
2778 if (key->key_type == KEY_WEP)
2779 wep_key_added = true;
2780 }
2781
2782 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002783 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002784 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002785 if (ret < 0)
2786 goto out;
2787 }
2788
2789out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002790 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002791 return ret;
2792}
2793
Eliad Peller536129c2011-10-05 11:55:45 +02002794static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2795 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002796 u8 key_size, const u8 *key, u32 tx_seq_32,
2797 u16 tx_seq_16, struct ieee80211_sta *sta)
2798{
2799 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002800 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002801
2802 if (is_ap) {
2803 struct wl1271_station *wl_sta;
2804 u8 hlid;
2805
2806 if (sta) {
2807 wl_sta = (struct wl1271_station *)sta->drv_priv;
2808 hlid = wl_sta->hlid;
2809 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002810 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002811 }
2812
Eliad Peller53d40d02011-10-10 10:13:02 +02002813 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002814 /*
2815 * We do not support removing keys after AP shutdown.
2816 * Pretend we do to make mac80211 happy.
2817 */
2818 if (action != KEY_ADD_OR_REPLACE)
2819 return 0;
2820
Eliad Peller170d0e62011-10-05 11:56:06 +02002821 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002822 key_type, key_size,
2823 key, hlid, tx_seq_32,
2824 tx_seq_16);
2825 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002826 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002827 id, key_type, key_size,
2828 key, hlid, tx_seq_32,
2829 tx_seq_16);
2830 }
2831
2832 if (ret < 0)
2833 return ret;
2834 } else {
2835 const u8 *addr;
2836 static const u8 bcast_addr[ETH_ALEN] = {
2837 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2838 };
2839
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002840 /*
2841 * A STA set to GEM cipher requires 2 tx spare blocks.
2842 * Return to default value when GEM cipher key is removed
2843 */
2844 if (key_type == KEY_GEM) {
2845 if (action == KEY_ADD_OR_REPLACE)
2846 wl->tx_spare_blocks = 2;
2847 else if (action == KEY_REMOVE)
2848 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2849 }
2850
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002851 addr = sta ? sta->addr : bcast_addr;
2852
2853 if (is_zero_ether_addr(addr)) {
2854 /* We dont support TX only encryption */
2855 return -EOPNOTSUPP;
2856 }
2857
2858 /* The wl1271 does not allow to remove unicast keys - they
2859 will be cleared automatically on next CMD_JOIN. Ignore the
2860 request silently, as we dont want the mac80211 to emit
2861 an error message. */
2862 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2863 return 0;
2864
Eliad Peller010d3d32011-08-14 13:17:31 +03002865 /* don't remove key if hlid was already deleted */
2866 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002867 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002868 return 0;
2869
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002870 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002871 id, key_type, key_size,
2872 key, addr, tx_seq_32,
2873 tx_seq_16);
2874 if (ret < 0)
2875 return ret;
2876
2877 /* the default WEP key needs to be configured at least once */
2878 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002879 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002880 wlvif->default_key,
2881 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002882 if (ret < 0)
2883 return ret;
2884 }
2885 }
2886
2887 return 0;
2888}
2889
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002890static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2891 struct ieee80211_vif *vif,
2892 struct ieee80211_sta *sta,
2893 struct ieee80211_key_conf *key_conf)
2894{
2895 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002896 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002897 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002898 u32 tx_seq_32 = 0;
2899 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002900 u8 key_type;
2901
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002902 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2903
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002904 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002905 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002906 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002907 key_conf->keylen, key_conf->flags);
2908 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2909
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002910 mutex_lock(&wl->mutex);
2911
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002912 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2913 ret = -EAGAIN;
2914 goto out_unlock;
2915 }
2916
Ido Yariva6208652011-03-01 15:14:41 +02002917 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002918 if (ret < 0)
2919 goto out_unlock;
2920
Johannes Berg97359d12010-08-10 09:46:38 +02002921 switch (key_conf->cipher) {
2922 case WLAN_CIPHER_SUITE_WEP40:
2923 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002924 key_type = KEY_WEP;
2925
2926 key_conf->hw_key_idx = key_conf->keyidx;
2927 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002928 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002929 key_type = KEY_TKIP;
2930
2931 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002932 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2933 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002934 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002935 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002936 key_type = KEY_AES;
2937
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002938 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002939 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2940 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002941 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002942 case WL1271_CIPHER_SUITE_GEM:
2943 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002944 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2945 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002946 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002947 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002948 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002949
2950 ret = -EOPNOTSUPP;
2951 goto out_sleep;
2952 }
2953
2954 switch (cmd) {
2955 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002956 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002957 key_conf->keyidx, key_type,
2958 key_conf->keylen, key_conf->key,
2959 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002960 if (ret < 0) {
2961 wl1271_error("Could not add or replace key");
2962 goto out_sleep;
2963 }
2964 break;
2965
2966 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002967 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002968 key_conf->keyidx, key_type,
2969 key_conf->keylen, key_conf->key,
2970 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002971 if (ret < 0) {
2972 wl1271_error("Could not remove key");
2973 goto out_sleep;
2974 }
2975 break;
2976
2977 default:
2978 wl1271_error("Unsupported key cmd 0x%x", cmd);
2979 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002980 break;
2981 }
2982
2983out_sleep:
2984 wl1271_ps_elp_sleep(wl);
2985
2986out_unlock:
2987 mutex_unlock(&wl->mutex);
2988
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002989 return ret;
2990}
2991
2992static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002993 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002994 struct cfg80211_scan_request *req)
2995{
2996 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02002997 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2998
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002999 int ret;
3000 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003001 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003002
3003 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3004
3005 if (req->n_ssids) {
3006 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003007 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003008 }
3009
3010 mutex_lock(&wl->mutex);
3011
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003012 if (wl->state == WL1271_STATE_OFF) {
3013 /*
3014 * We cannot return -EBUSY here because cfg80211 will expect
3015 * a call to ieee80211_scan_completed if we do - in this case
3016 * there won't be any call.
3017 */
3018 ret = -EAGAIN;
3019 goto out;
3020 }
3021
Ido Yariva6208652011-03-01 15:14:41 +02003022 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003023 if (ret < 0)
3024 goto out;
3025
Eliad Peller92e712d2011-12-18 20:25:43 +02003026 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
3027 test_bit(wlvif->role_id, wl->roc_map)) {
3028 /* don't allow scanning right now */
3029 ret = -EBUSY;
3030 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003031 }
3032
Eliad Peller92e712d2011-12-18 20:25:43 +02003033 /* cancel ROC before scanning */
3034 if (wl12xx_dev_role_started(wlvif))
3035 wl12xx_stop_dev(wl, wlvif);
3036
Eliad Peller784f6942011-10-05 11:55:39 +02003037 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003038out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003039 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003040out:
3041 mutex_unlock(&wl->mutex);
3042
3043 return ret;
3044}
3045
Eliad Peller73ecce32011-06-27 13:06:45 +03003046static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3047 struct ieee80211_vif *vif)
3048{
3049 struct wl1271 *wl = hw->priv;
3050 int ret;
3051
3052 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3053
3054 mutex_lock(&wl->mutex);
3055
3056 if (wl->state == WL1271_STATE_OFF)
3057 goto out;
3058
3059 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3060 goto out;
3061
3062 ret = wl1271_ps_elp_wakeup(wl);
3063 if (ret < 0)
3064 goto out;
3065
3066 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3067 ret = wl1271_scan_stop(wl);
3068 if (ret < 0)
3069 goto out_sleep;
3070 }
3071 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3072 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003073 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003074 wl->scan.req = NULL;
3075 ieee80211_scan_completed(wl->hw, true);
3076
3077out_sleep:
3078 wl1271_ps_elp_sleep(wl);
3079out:
3080 mutex_unlock(&wl->mutex);
3081
3082 cancel_delayed_work_sync(&wl->scan_complete_work);
3083}
3084
Luciano Coelho33c2c062011-05-10 14:46:02 +03003085static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3086 struct ieee80211_vif *vif,
3087 struct cfg80211_sched_scan_request *req,
3088 struct ieee80211_sched_scan_ies *ies)
3089{
3090 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003091 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003092 int ret;
3093
3094 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3095
3096 mutex_lock(&wl->mutex);
3097
3098 ret = wl1271_ps_elp_wakeup(wl);
3099 if (ret < 0)
3100 goto out;
3101
Eliad Peller536129c2011-10-05 11:55:45 +02003102 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003103 if (ret < 0)
3104 goto out_sleep;
3105
Eliad Peller536129c2011-10-05 11:55:45 +02003106 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003107 if (ret < 0)
3108 goto out_sleep;
3109
3110 wl->sched_scanning = true;
3111
3112out_sleep:
3113 wl1271_ps_elp_sleep(wl);
3114out:
3115 mutex_unlock(&wl->mutex);
3116 return ret;
3117}
3118
3119static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3120 struct ieee80211_vif *vif)
3121{
3122 struct wl1271 *wl = hw->priv;
3123 int ret;
3124
3125 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3126
3127 mutex_lock(&wl->mutex);
3128
3129 ret = wl1271_ps_elp_wakeup(wl);
3130 if (ret < 0)
3131 goto out;
3132
3133 wl1271_scan_sched_scan_stop(wl);
3134
3135 wl1271_ps_elp_sleep(wl);
3136out:
3137 mutex_unlock(&wl->mutex);
3138}
3139
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003140static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3141{
3142 struct wl1271 *wl = hw->priv;
3143 int ret = 0;
3144
3145 mutex_lock(&wl->mutex);
3146
3147 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3148 ret = -EAGAIN;
3149 goto out;
3150 }
3151
Ido Yariva6208652011-03-01 15:14:41 +02003152 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003153 if (ret < 0)
3154 goto out;
3155
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003156 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003157 if (ret < 0)
3158 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3159
3160 wl1271_ps_elp_sleep(wl);
3161
3162out:
3163 mutex_unlock(&wl->mutex);
3164
3165 return ret;
3166}
3167
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003168static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3169{
3170 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003171 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003172 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003173
3174 mutex_lock(&wl->mutex);
3175
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003176 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3177 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003178 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003179 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003180
Ido Yariva6208652011-03-01 15:14:41 +02003181 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003182 if (ret < 0)
3183 goto out;
3184
Eliad Peller6e8cd332011-10-10 10:13:13 +02003185 wl12xx_for_each_wlvif(wl, wlvif) {
3186 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3187 if (ret < 0)
3188 wl1271_warning("set rts threshold failed: %d", ret);
3189 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003190 wl1271_ps_elp_sleep(wl);
3191
3192out:
3193 mutex_unlock(&wl->mutex);
3194
3195 return ret;
3196}
3197
Eliad Peller1fe9f162011-10-05 11:55:48 +02003198static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003199 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003200{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003201 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003202 u8 ssid_len;
3203 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3204 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003205
Eliad Peller889cb362011-05-01 09:56:45 +03003206 if (!ptr) {
3207 wl1271_error("No SSID in IEs!");
3208 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003209 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003210
Eliad Peller889cb362011-05-01 09:56:45 +03003211 ssid_len = ptr[1];
3212 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3213 wl1271_error("SSID is too long!");
3214 return -EINVAL;
3215 }
3216
Eliad Peller1fe9f162011-10-05 11:55:48 +02003217 wlvif->ssid_len = ssid_len;
3218 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003219 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003220}
3221
Eliad Pellerd48055d2011-09-15 12:07:04 +03003222static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3223{
3224 int len;
3225 const u8 *next, *end = skb->data + skb->len;
3226 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3227 skb->len - ieoffset);
3228 if (!ie)
3229 return;
3230 len = ie[1] + 2;
3231 next = ie + len;
3232 memmove(ie, next, end - next);
3233 skb_trim(skb, skb->len - len);
3234}
3235
Eliad Peller26b4bf22011-09-15 12:07:05 +03003236static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3237 unsigned int oui, u8 oui_type,
3238 int ieoffset)
3239{
3240 int len;
3241 const u8 *next, *end = skb->data + skb->len;
3242 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3243 skb->data + ieoffset,
3244 skb->len - ieoffset);
3245 if (!ie)
3246 return;
3247 len = ie[1] + 2;
3248 next = ie + len;
3249 memmove(ie, next, end - next);
3250 skb_trim(skb, skb->len - len);
3251}
3252
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003253static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3254 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003255{
3256 struct sk_buff *skb;
3257 int ret;
3258
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003259 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003260 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003261 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003262
3263 ret = wl1271_cmd_template_set(wl,
3264 CMD_TEMPL_AP_PROBE_RESPONSE,
3265 skb->data,
3266 skb->len, 0,
3267 rates);
3268
3269 dev_kfree_skb(skb);
3270 return ret;
3271}
3272
3273static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3274 struct ieee80211_vif *vif,
3275 u8 *probe_rsp_data,
3276 size_t probe_rsp_len,
3277 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003278{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003279 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3280 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003281 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3282 int ssid_ie_offset, ie_offset, templ_len;
3283 const u8 *ptr;
3284
3285 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003286 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003287 return wl1271_cmd_template_set(wl,
3288 CMD_TEMPL_AP_PROBE_RESPONSE,
3289 probe_rsp_data,
3290 probe_rsp_len, 0,
3291 rates);
3292
3293 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3294 wl1271_error("probe_rsp template too big");
3295 return -EINVAL;
3296 }
3297
3298 /* start searching from IE offset */
3299 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3300
3301 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3302 probe_rsp_len - ie_offset);
3303 if (!ptr) {
3304 wl1271_error("No SSID in beacon!");
3305 return -EINVAL;
3306 }
3307
3308 ssid_ie_offset = ptr - probe_rsp_data;
3309 ptr += (ptr[1] + 2);
3310
3311 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3312
3313 /* insert SSID from bss_conf */
3314 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3315 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3316 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3317 bss_conf->ssid, bss_conf->ssid_len);
3318 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3319
3320 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3321 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3322 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3323
3324 return wl1271_cmd_template_set(wl,
3325 CMD_TEMPL_AP_PROBE_RESPONSE,
3326 probe_rsp_templ,
3327 templ_len, 0,
3328 rates);
3329}
3330
Arik Nemtsove78a2872010-10-16 19:07:21 +02003331static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003332 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003333 struct ieee80211_bss_conf *bss_conf,
3334 u32 changed)
3335{
Eliad Peller0603d892011-10-05 11:55:51 +02003336 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003337 int ret = 0;
3338
3339 if (changed & BSS_CHANGED_ERP_SLOT) {
3340 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003341 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003342 else
Eliad Peller0603d892011-10-05 11:55:51 +02003343 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003344 if (ret < 0) {
3345 wl1271_warning("Set slot time failed %d", ret);
3346 goto out;
3347 }
3348 }
3349
3350 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3351 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003352 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003353 else
Eliad Peller0603d892011-10-05 11:55:51 +02003354 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003355 }
3356
3357 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3358 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003359 ret = wl1271_acx_cts_protect(wl, wlvif,
3360 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003361 else
Eliad Peller0603d892011-10-05 11:55:51 +02003362 ret = wl1271_acx_cts_protect(wl, wlvif,
3363 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003364 if (ret < 0) {
3365 wl1271_warning("Set ctsprotect failed %d", ret);
3366 goto out;
3367 }
3368 }
3369
3370out:
3371 return ret;
3372}
3373
3374static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3375 struct ieee80211_vif *vif,
3376 struct ieee80211_bss_conf *bss_conf,
3377 u32 changed)
3378{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003379 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003380 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003381 int ret = 0;
3382
3383 if ((changed & BSS_CHANGED_BEACON_INT)) {
3384 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3385 bss_conf->beacon_int);
3386
Eliad Peller6a899792011-10-05 11:55:58 +02003387 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003388 }
3389
Arik Nemtsov560f0022011-11-08 18:46:54 +02003390 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3391 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003392 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3393 wl1271_debug(DEBUG_AP, "probe response updated");
3394 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3395 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003396 }
3397
Arik Nemtsove78a2872010-10-16 19:07:21 +02003398 if ((changed & BSS_CHANGED_BEACON)) {
3399 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003400 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003401 int ieoffset = offsetof(struct ieee80211_mgmt,
3402 u.beacon.variable);
3403 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3404 u16 tmpl_id;
3405
Arik Nemtsov560f0022011-11-08 18:46:54 +02003406 if (!beacon) {
3407 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003408 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003409 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003410
3411 wl1271_debug(DEBUG_MASTER, "beacon updated");
3412
Eliad Peller1fe9f162011-10-05 11:55:48 +02003413 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003414 if (ret < 0) {
3415 dev_kfree_skb(beacon);
3416 goto out;
3417 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003418 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003419 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3420 CMD_TEMPL_BEACON;
3421 ret = wl1271_cmd_template_set(wl, tmpl_id,
3422 beacon->data,
3423 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003424 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003425 if (ret < 0) {
3426 dev_kfree_skb(beacon);
3427 goto out;
3428 }
3429
Arik Nemtsov560f0022011-11-08 18:46:54 +02003430 /*
3431 * In case we already have a probe-resp beacon set explicitly
3432 * by usermode, don't use the beacon data.
3433 */
3434 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3435 goto end_bcn;
3436
Eliad Pellerd48055d2011-09-15 12:07:04 +03003437 /* remove TIM ie from probe response */
3438 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3439
Eliad Peller26b4bf22011-09-15 12:07:05 +03003440 /*
3441 * remove p2p ie from probe response.
3442 * the fw reponds to probe requests that don't include
3443 * the p2p ie. probe requests with p2p ie will be passed,
3444 * and will be responded by the supplicant (the spec
3445 * forbids including the p2p ie when responding to probe
3446 * requests that didn't include it).
3447 */
3448 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3449 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3450
Arik Nemtsove78a2872010-10-16 19:07:21 +02003451 hdr = (struct ieee80211_hdr *) beacon->data;
3452 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3453 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003454 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003455 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003456 beacon->data,
3457 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003458 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003459 else
3460 ret = wl1271_cmd_template_set(wl,
3461 CMD_TEMPL_PROBE_RESPONSE,
3462 beacon->data,
3463 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003464 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003465end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003466 dev_kfree_skb(beacon);
3467 if (ret < 0)
3468 goto out;
3469 }
3470
3471out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003472 if (ret != 0)
3473 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003474 return ret;
3475}
3476
3477/* AP mode changes */
3478static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003479 struct ieee80211_vif *vif,
3480 struct ieee80211_bss_conf *bss_conf,
3481 u32 changed)
3482{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003483 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003484 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003485
Arik Nemtsove78a2872010-10-16 19:07:21 +02003486 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3487 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003488
Eliad Peller87fbcb02011-10-05 11:55:41 +02003489 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003490 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003491 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003492 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003493
Eliad Peller87fbcb02011-10-05 11:55:41 +02003494 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003495 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003496 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003497 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003498 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003499
Eliad Peller784f6942011-10-05 11:55:39 +02003500 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003501 if (ret < 0)
3502 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003503 }
3504
Arik Nemtsove78a2872010-10-16 19:07:21 +02003505 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3506 if (ret < 0)
3507 goto out;
3508
3509 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3510 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003511 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003512 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003513 if (ret < 0)
3514 goto out;
3515
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003516 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003517 if (ret < 0)
3518 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003519
Eliad Peller53d40d02011-10-10 10:13:02 +02003520 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003521 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003522 }
3523 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003524 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003525 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003526 if (ret < 0)
3527 goto out;
3528
Eliad Peller53d40d02011-10-10 10:13:02 +02003529 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003530 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3531 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003532 wl1271_debug(DEBUG_AP, "stopped AP");
3533 }
3534 }
3535 }
3536
Eliad Peller0603d892011-10-05 11:55:51 +02003537 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003538 if (ret < 0)
3539 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003540
3541 /* Handle HT information change */
3542 if ((changed & BSS_CHANGED_HT) &&
3543 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003544 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003545 bss_conf->ht_operation_mode);
3546 if (ret < 0) {
3547 wl1271_warning("Set ht information failed %d", ret);
3548 goto out;
3549 }
3550 }
3551
Arik Nemtsove78a2872010-10-16 19:07:21 +02003552out:
3553 return;
3554}
3555
3556/* STA/IBSS mode changes */
3557static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3558 struct ieee80211_vif *vif,
3559 struct ieee80211_bss_conf *bss_conf,
3560 u32 changed)
3561{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003562 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003563 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003564 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003565 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003566 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003567 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003568 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003569 bool sta_exists = false;
3570 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003571
3572 if (is_ibss) {
3573 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3574 changed);
3575 if (ret < 0)
3576 goto out;
3577 }
3578
Eliad Peller227e81e2011-08-14 13:17:26 +03003579 if (changed & BSS_CHANGED_IBSS) {
3580 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003581 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003582 ibss_joined = true;
3583 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003584 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3585 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003586 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003587 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003588 }
3589 }
3590 }
3591
3592 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003593 do_join = true;
3594
3595 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003596 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003597 do_join = true;
3598
Eliad Peller227e81e2011-08-14 13:17:26 +03003599 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003600 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3601 bss_conf->enable_beacon ? "enabled" : "disabled");
3602
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003603 do_join = true;
3604 }
3605
Eliad Pellerc31e4942011-10-23 08:21:55 +02003606 if (changed & BSS_CHANGED_IDLE) {
3607 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3608 if (ret < 0)
3609 wl1271_warning("idle mode change failed %d", ret);
3610 }
3611
Arik Nemtsove78a2872010-10-16 19:07:21 +02003612 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003613 bool enable = false;
3614 if (bss_conf->cqm_rssi_thold)
3615 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003616 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003617 bss_conf->cqm_rssi_thold,
3618 bss_conf->cqm_rssi_hyst);
3619 if (ret < 0)
3620 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003621 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003622 }
3623
Eliad Pellercdf09492011-10-05 11:55:44 +02003624 if (changed & BSS_CHANGED_BSSID)
3625 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003626 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003627 if (ret < 0)
3628 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003629
Eliad Peller784f6942011-10-05 11:55:39 +02003630 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003631 if (ret < 0)
3632 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003633
Eliad Pellerfa287b82010-12-26 09:27:50 +01003634 /* Need to update the BSSID (for filtering etc) */
3635 do_join = true;
3636 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003637
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003638 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3639 rcu_read_lock();
3640 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3641 if (!sta)
3642 goto sta_not_found;
3643
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003644 /* save the supp_rates of the ap */
3645 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3646 if (sta->ht_cap.ht_supported)
3647 sta_rate_set |=
3648 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003649 sta_ht_cap = sta->ht_cap;
3650 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003651
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003652sta_not_found:
3653 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003654 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003655
Arik Nemtsove78a2872010-10-16 19:07:21 +02003656 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003657 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003658 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003659 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003660 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003661 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003662
Eliad Peller74ec8392011-10-05 11:56:02 +02003663 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003664
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003665 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003666 * use basic rates from AP, and determine lowest rate
3667 * to use with control frames.
3668 */
3669 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003670 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003671 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003672 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003673 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003674 wl1271_tx_min_rate_get(wl,
3675 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003676 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003677 wlvif->rate_set =
3678 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003679 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003680 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003681 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003682 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003683 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003684
3685 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003686 * with wl1271, we don't need to update the
3687 * beacon_int and dtim_period, because the firmware
3688 * updates it by itself when the first beacon is
3689 * received after a join.
3690 */
Eliad Peller6840e372011-10-05 11:55:50 +02003691 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003692 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003693 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003694
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003695 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003696 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003697 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003698 dev_kfree_skb(wlvif->probereq);
3699 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003700 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003701 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003702 ieoffset = offsetof(struct ieee80211_mgmt,
3703 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003704 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003705
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003706 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003707 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003708 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003709 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003710 } else {
3711 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003712 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003713 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3714 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003715 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003716 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3717 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003718 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003719
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003720 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003721 dev_kfree_skb(wlvif->probereq);
3722 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003723
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003724 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003725 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003726
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003727 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003728 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003729 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003730 wl1271_tx_min_rate_get(wl,
3731 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003732 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003733 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003734 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003735
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003736 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003737 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003738
3739 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003740 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003741 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003742 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003743
3744 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003745 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003746 u32 conf_flags = wl->hw->conf.flags;
3747 /*
3748 * we might have to disable roc, if there was
3749 * no IF_OPER_UP notification.
3750 */
3751 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003752 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003753 if (ret < 0)
3754 goto out;
3755 }
3756 /*
3757 * (we also need to disable roc in case of
3758 * roaming on the same channel. until we will
3759 * have a better flow...)
3760 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003761 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3762 ret = wl12xx_croc(wl,
3763 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003764 if (ret < 0)
3765 goto out;
3766 }
3767
Eliad Peller0603d892011-10-05 11:55:51 +02003768 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003769 if (!(conf_flags & IEEE80211_CONF_IDLE))
3770 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003771 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003772 }
3773 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003774
Eliad Pellerd192d262011-05-24 14:33:08 +03003775 if (changed & BSS_CHANGED_IBSS) {
3776 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3777 bss_conf->ibss_joined);
3778
3779 if (bss_conf->ibss_joined) {
3780 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003781 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003782 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003783 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003784 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003785 wl1271_tx_min_rate_get(wl,
3786 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003787
Shahar Levi06b660e2011-09-05 13:54:36 +03003788 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003789 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3790 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003791 if (ret < 0)
3792 goto out;
3793 }
3794 }
3795
Eliad Peller0603d892011-10-05 11:55:51 +02003796 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003797 if (ret < 0)
3798 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003799
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003800 if (changed & BSS_CHANGED_ARP_FILTER) {
3801 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003802 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003803
Eliad Pellerc5312772010-12-09 11:31:27 +02003804 if (bss_conf->arp_addr_cnt == 1 &&
3805 bss_conf->arp_filter_enabled) {
3806 /*
3807 * The template should have been configured only upon
3808 * association. however, it seems that the correct ip
3809 * isn't being set (when sending), so we have to
3810 * reconfigure the template upon every ip change.
3811 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003812 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003813 if (ret < 0) {
3814 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003815 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003816 }
3817
Eliad Peller0603d892011-10-05 11:55:51 +02003818 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003819 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003820 addr);
3821 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003822 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003823
3824 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003825 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003826 }
3827
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003828 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003829 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003830 if (ret < 0) {
3831 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003832 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003833 }
Eliad Peller251c1772011-08-14 13:17:17 +03003834
3835 /* ROC until connected (after EAPOL exchange) */
3836 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003837 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003838 if (ret < 0)
3839 goto out;
3840
Eliad Pellerba8447f2011-10-10 10:13:00 +02003841 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003842 ieee80211_get_operstate(vif));
3843 }
3844 /*
3845 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003846 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003847 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003848 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003849 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003850 if (ret < 0)
3851 goto out;
3852 }
Eliad Peller05dba352011-08-23 16:37:01 +03003853
3854 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003855 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3856 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003857 enum wl1271_cmd_ps_mode mode;
3858
3859 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003860 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003861 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003862 true);
3863 if (ret < 0)
3864 goto out;
3865 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003866 }
3867
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003868 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003869 if (sta_exists) {
3870 if ((changed & BSS_CHANGED_HT) &&
3871 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003872 ret = wl1271_acx_set_ht_capabilities(wl,
3873 &sta_ht_cap,
3874 true,
Eliad Peller154da672011-10-05 11:55:53 +02003875 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003876 if (ret < 0) {
3877 wl1271_warning("Set ht cap true failed %d",
3878 ret);
3879 goto out;
3880 }
3881 }
3882 /* handle new association without HT and disassociation */
3883 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003884 ret = wl1271_acx_set_ht_capabilities(wl,
3885 &sta_ht_cap,
3886 false,
Eliad Peller154da672011-10-05 11:55:53 +02003887 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003888 if (ret < 0) {
3889 wl1271_warning("Set ht cap false failed %d",
3890 ret);
3891 goto out;
3892 }
3893 }
3894 }
3895
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003896 /* Handle HT information change. Done after join. */
3897 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003898 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003899 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003900 bss_conf->ht_operation_mode);
3901 if (ret < 0) {
3902 wl1271_warning("Set ht information failed %d", ret);
3903 goto out;
3904 }
3905 }
3906
Arik Nemtsove78a2872010-10-16 19:07:21 +02003907out:
3908 return;
3909}
3910
3911static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3912 struct ieee80211_vif *vif,
3913 struct ieee80211_bss_conf *bss_conf,
3914 u32 changed)
3915{
3916 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003917 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3918 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003919 int ret;
3920
3921 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3922 (int)changed);
3923
3924 mutex_lock(&wl->mutex);
3925
3926 if (unlikely(wl->state == WL1271_STATE_OFF))
3927 goto out;
3928
Eliad Peller10c8cd02011-10-10 10:13:06 +02003929 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3930 goto out;
3931
Ido Yariva6208652011-03-01 15:14:41 +02003932 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003933 if (ret < 0)
3934 goto out;
3935
3936 if (is_ap)
3937 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3938 else
3939 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3940
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003941 wl1271_ps_elp_sleep(wl);
3942
3943out:
3944 mutex_unlock(&wl->mutex);
3945}
3946
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003947static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3948 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003949 const struct ieee80211_tx_queue_params *params)
3950{
3951 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003952 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003953 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003954 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003955
3956 mutex_lock(&wl->mutex);
3957
3958 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3959
Kalle Valo4695dc92010-03-18 12:26:38 +02003960 if (params->uapsd)
3961 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3962 else
3963 ps_scheme = CONF_PS_SCHEME_LEGACY;
3964
Eliad Peller5b37ddf2011-12-18 20:25:40 +02003965 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003966 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003967
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003968 ret = wl1271_ps_elp_wakeup(wl);
3969 if (ret < 0)
3970 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003971
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003972 /*
3973 * the txop is confed in units of 32us by the mac80211,
3974 * we need us
3975 */
Eliad Peller0603d892011-10-05 11:55:51 +02003976 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003977 params->cw_min, params->cw_max,
3978 params->aifs, params->txop << 5);
3979 if (ret < 0)
3980 goto out_sleep;
3981
Eliad Peller0603d892011-10-05 11:55:51 +02003982 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003983 CONF_CHANNEL_TYPE_EDCF,
3984 wl1271_tx_get_queue(queue),
3985 ps_scheme, CONF_ACK_POLICY_LEGACY,
3986 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003987
3988out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003989 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003990
3991out:
3992 mutex_unlock(&wl->mutex);
3993
3994 return ret;
3995}
3996
Eliad Peller37a41b42011-09-21 14:06:11 +03003997static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
3998 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003999{
4000
4001 struct wl1271 *wl = hw->priv;
4002 u64 mactime = ULLONG_MAX;
4003 int ret;
4004
4005 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4006
4007 mutex_lock(&wl->mutex);
4008
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004009 if (unlikely(wl->state == WL1271_STATE_OFF))
4010 goto out;
4011
Ido Yariva6208652011-03-01 15:14:41 +02004012 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004013 if (ret < 0)
4014 goto out;
4015
4016 ret = wl1271_acx_tsf_info(wl, &mactime);
4017 if (ret < 0)
4018 goto out_sleep;
4019
4020out_sleep:
4021 wl1271_ps_elp_sleep(wl);
4022
4023out:
4024 mutex_unlock(&wl->mutex);
4025 return mactime;
4026}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004027
John W. Linvilleece550d2010-07-28 16:41:06 -04004028static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4029 struct survey_info *survey)
4030{
4031 struct wl1271 *wl = hw->priv;
4032 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004033
John W. Linvilleece550d2010-07-28 16:41:06 -04004034 if (idx != 0)
4035 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004036
John W. Linvilleece550d2010-07-28 16:41:06 -04004037 survey->channel = conf->channel;
4038 survey->filled = SURVEY_INFO_NOISE_DBM;
4039 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004040
John W. Linvilleece550d2010-07-28 16:41:06 -04004041 return 0;
4042}
4043
Arik Nemtsov409622e2011-02-23 00:22:29 +02004044static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004045 struct wl12xx_vif *wlvif,
4046 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004047{
4048 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004049 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004050
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004051
4052 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004053 wl1271_warning("could not allocate HLID - too much stations");
4054 return -EBUSY;
4055 }
4056
4057 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004058 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4059 if (ret < 0) {
4060 wl1271_warning("could not allocate HLID - too many links");
4061 return -EBUSY;
4062 }
4063
4064 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004065 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004066 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004067 return 0;
4068}
4069
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004070void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004071{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004072 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004073 return;
4074
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004075 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004076 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004077 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004078 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004079 __clear_bit(hlid, &wl->ap_ps_map);
4080 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004081 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004082 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004083}
4084
4085static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4086 struct ieee80211_vif *vif,
4087 struct ieee80211_sta *sta)
4088{
4089 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004090 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004091 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004092 int ret = 0;
4093 u8 hlid;
4094
4095 mutex_lock(&wl->mutex);
4096
4097 if (unlikely(wl->state == WL1271_STATE_OFF))
4098 goto out;
4099
Eliad Peller536129c2011-10-05 11:55:45 +02004100 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004101 goto out;
4102
4103 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4104
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004105 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004106 if (ret < 0)
4107 goto out;
4108
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004109 wl_sta = (struct wl1271_station *)sta->drv_priv;
4110 hlid = wl_sta->hlid;
4111
Ido Yariva6208652011-03-01 15:14:41 +02004112 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004113 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004114 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004115
Eliad Peller1b92f152011-10-10 10:13:09 +02004116 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004117 if (ret < 0)
4118 goto out_sleep;
4119
Eliad Pellerb67476e2011-08-14 13:17:23 +03004120 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4121 if (ret < 0)
4122 goto out_sleep;
4123
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004124 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4125 if (ret < 0)
4126 goto out_sleep;
4127
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004128out_sleep:
4129 wl1271_ps_elp_sleep(wl);
4130
Arik Nemtsov409622e2011-02-23 00:22:29 +02004131out_free_sta:
4132 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004133 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004134
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004135out:
4136 mutex_unlock(&wl->mutex);
4137 return ret;
4138}
4139
4140static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4141 struct ieee80211_vif *vif,
4142 struct ieee80211_sta *sta)
4143{
4144 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004145 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004146 struct wl1271_station *wl_sta;
4147 int ret = 0, id;
4148
4149 mutex_lock(&wl->mutex);
4150
4151 if (unlikely(wl->state == WL1271_STATE_OFF))
4152 goto out;
4153
Eliad Peller536129c2011-10-05 11:55:45 +02004154 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004155 goto out;
4156
4157 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4158
4159 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004160 id = wl_sta->hlid;
4161 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004162 goto out;
4163
Ido Yariva6208652011-03-01 15:14:41 +02004164 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004165 if (ret < 0)
4166 goto out;
4167
Eliad Pellerc690ec82011-08-14 13:17:07 +03004168 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004169 if (ret < 0)
4170 goto out_sleep;
4171
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004172 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004173
4174out_sleep:
4175 wl1271_ps_elp_sleep(wl);
4176
4177out:
4178 mutex_unlock(&wl->mutex);
4179 return ret;
4180}
4181
Luciano Coelho4623ec72011-03-21 19:26:41 +02004182static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4183 struct ieee80211_vif *vif,
4184 enum ieee80211_ampdu_mlme_action action,
4185 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4186 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004187{
4188 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004189 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004190 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004191 u8 hlid, *ba_bitmap;
4192
4193 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4194 tid);
4195
4196 /* sanity check - the fields in FW are only 8bits wide */
4197 if (WARN_ON(tid > 0xFF))
4198 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004199
4200 mutex_lock(&wl->mutex);
4201
4202 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4203 ret = -EAGAIN;
4204 goto out;
4205 }
4206
Eliad Peller536129c2011-10-05 11:55:45 +02004207 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004208 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004209 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004210 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004211 struct wl1271_station *wl_sta;
4212
4213 wl_sta = (struct wl1271_station *)sta->drv_priv;
4214 hlid = wl_sta->hlid;
4215 ba_bitmap = &wl->links[hlid].ba_bitmap;
4216 } else {
4217 ret = -EINVAL;
4218 goto out;
4219 }
4220
Ido Yariva6208652011-03-01 15:14:41 +02004221 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004222 if (ret < 0)
4223 goto out;
4224
Shahar Levi70559a02011-05-22 16:10:22 +03004225 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4226 tid, action);
4227
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004228 switch (action) {
4229 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004230 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004231 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004232 break;
4233 }
4234
4235 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4236 ret = -EBUSY;
4237 wl1271_error("exceeded max RX BA sessions");
4238 break;
4239 }
4240
4241 if (*ba_bitmap & BIT(tid)) {
4242 ret = -EINVAL;
4243 wl1271_error("cannot enable RX BA session on active "
4244 "tid: %d", tid);
4245 break;
4246 }
4247
4248 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4249 hlid);
4250 if (!ret) {
4251 *ba_bitmap |= BIT(tid);
4252 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004253 }
4254 break;
4255
4256 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004257 if (!(*ba_bitmap & BIT(tid))) {
4258 ret = -EINVAL;
4259 wl1271_error("no active RX BA session on tid: %d",
4260 tid);
4261 break;
4262 }
4263
4264 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4265 hlid);
4266 if (!ret) {
4267 *ba_bitmap &= ~BIT(tid);
4268 wl->ba_rx_session_count--;
4269 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004270 break;
4271
4272 /*
4273 * The BA initiator session management in FW independently.
4274 * Falling break here on purpose for all TX APDU commands.
4275 */
4276 case IEEE80211_AMPDU_TX_START:
4277 case IEEE80211_AMPDU_TX_STOP:
4278 case IEEE80211_AMPDU_TX_OPERATIONAL:
4279 ret = -EINVAL;
4280 break;
4281
4282 default:
4283 wl1271_error("Incorrect ampdu action id=%x\n", action);
4284 ret = -EINVAL;
4285 }
4286
4287 wl1271_ps_elp_sleep(wl);
4288
4289out:
4290 mutex_unlock(&wl->mutex);
4291
4292 return ret;
4293}
4294
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004295static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4296 struct ieee80211_vif *vif,
4297 const struct cfg80211_bitrate_mask *mask)
4298{
Eliad Peller83587502011-10-10 10:12:53 +02004299 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004300 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004301 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004302
4303 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4304 mask->control[NL80211_BAND_2GHZ].legacy,
4305 mask->control[NL80211_BAND_5GHZ].legacy);
4306
4307 mutex_lock(&wl->mutex);
4308
4309 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004310 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004311 wl1271_tx_enabled_rates_get(wl,
4312 mask->control[i].legacy,
4313 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004314
4315 if (unlikely(wl->state == WL1271_STATE_OFF))
4316 goto out;
4317
4318 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4319 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4320
4321 ret = wl1271_ps_elp_wakeup(wl);
4322 if (ret < 0)
4323 goto out;
4324
4325 wl1271_set_band_rate(wl, wlvif);
4326 wlvif->basic_rate =
4327 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4328 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4329
4330 wl1271_ps_elp_sleep(wl);
4331 }
4332out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004333 mutex_unlock(&wl->mutex);
4334
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004335 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004336}
4337
Shahar Levi6d158ff2011-09-08 13:01:33 +03004338static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4339 struct ieee80211_channel_switch *ch_switch)
4340{
4341 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004342 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004343 int ret;
4344
4345 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4346
4347 mutex_lock(&wl->mutex);
4348
4349 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004350 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4351 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4352 ieee80211_chswitch_done(vif, false);
4353 }
4354 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004355 }
4356
4357 ret = wl1271_ps_elp_wakeup(wl);
4358 if (ret < 0)
4359 goto out;
4360
Eliad Peller52630c52011-10-10 10:13:08 +02004361 /* TODO: change mac80211 to pass vif as param */
4362 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4363 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004364
Eliad Peller52630c52011-10-10 10:13:08 +02004365 if (!ret)
4366 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4367 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004368
4369 wl1271_ps_elp_sleep(wl);
4370
4371out:
4372 mutex_unlock(&wl->mutex);
4373}
4374
Arik Nemtsov33437892011-04-26 23:35:39 +03004375static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4376{
4377 struct wl1271 *wl = hw->priv;
4378 bool ret = false;
4379
4380 mutex_lock(&wl->mutex);
4381
4382 if (unlikely(wl->state == WL1271_STATE_OFF))
4383 goto out;
4384
4385 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004386 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004387out:
4388 mutex_unlock(&wl->mutex);
4389
4390 return ret;
4391}
4392
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004393/* can't be const, mac80211 writes to this */
4394static struct ieee80211_rate wl1271_rates[] = {
4395 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004396 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4397 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004398 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004399 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4400 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004401 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4402 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004403 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4404 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004405 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4406 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004407 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4408 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004409 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4410 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004411 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4412 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004413 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004414 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4415 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004416 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004417 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4418 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004419 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004420 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4421 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004422 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004423 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4424 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004425 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004426 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4427 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004428 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004429 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4430 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004431 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004432 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4433 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004434};
4435
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004436/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004437static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004438 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004439 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004440 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4441 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4442 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004443 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004444 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4445 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4446 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004447 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004448 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4449 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4450 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004451 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004452};
4453
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004454/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004455static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004456 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004457 7, /* CONF_HW_RXTX_RATE_MCS7 */
4458 6, /* CONF_HW_RXTX_RATE_MCS6 */
4459 5, /* CONF_HW_RXTX_RATE_MCS5 */
4460 4, /* CONF_HW_RXTX_RATE_MCS4 */
4461 3, /* CONF_HW_RXTX_RATE_MCS3 */
4462 2, /* CONF_HW_RXTX_RATE_MCS2 */
4463 1, /* CONF_HW_RXTX_RATE_MCS1 */
4464 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004465
4466 11, /* CONF_HW_RXTX_RATE_54 */
4467 10, /* CONF_HW_RXTX_RATE_48 */
4468 9, /* CONF_HW_RXTX_RATE_36 */
4469 8, /* CONF_HW_RXTX_RATE_24 */
4470
4471 /* TI-specific rate */
4472 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4473
4474 7, /* CONF_HW_RXTX_RATE_18 */
4475 6, /* CONF_HW_RXTX_RATE_12 */
4476 3, /* CONF_HW_RXTX_RATE_11 */
4477 5, /* CONF_HW_RXTX_RATE_9 */
4478 4, /* CONF_HW_RXTX_RATE_6 */
4479 2, /* CONF_HW_RXTX_RATE_5_5 */
4480 1, /* CONF_HW_RXTX_RATE_2 */
4481 0 /* CONF_HW_RXTX_RATE_1 */
4482};
4483
Shahar Levie8b03a22010-10-13 16:09:39 +02004484/* 11n STA capabilities */
4485#define HW_RX_HIGHEST_RATE 72
4486
Shahar Levi00d20102010-11-08 11:20:10 +00004487#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004488 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4489 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004490 .ht_supported = true, \
4491 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4492 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4493 .mcs = { \
4494 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4495 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4496 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4497 }, \
4498}
4499
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004500/* can't be const, mac80211 writes to this */
4501static struct ieee80211_supported_band wl1271_band_2ghz = {
4502 .channels = wl1271_channels,
4503 .n_channels = ARRAY_SIZE(wl1271_channels),
4504 .bitrates = wl1271_rates,
4505 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004506 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004507};
4508
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004509/* 5 GHz data rates for WL1273 */
4510static struct ieee80211_rate wl1271_rates_5ghz[] = {
4511 { .bitrate = 60,
4512 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4513 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4514 { .bitrate = 90,
4515 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4516 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4517 { .bitrate = 120,
4518 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4519 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4520 { .bitrate = 180,
4521 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4522 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4523 { .bitrate = 240,
4524 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4525 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4526 { .bitrate = 360,
4527 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4528 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4529 { .bitrate = 480,
4530 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4531 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4532 { .bitrate = 540,
4533 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4534 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4535};
4536
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004537/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004538static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004539 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4540 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4541 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4542 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4543 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4544 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4545 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4546 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4547 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4548 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4549 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4550 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4551 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4552 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4553 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4554 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4555 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4556 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4557 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4558 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4559 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4560 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4561 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4562 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4563 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4564 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4565 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4566 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4567 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4568 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4569 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4570 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4571 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4572 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004573};
4574
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004575/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004576static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004577 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004578 7, /* CONF_HW_RXTX_RATE_MCS7 */
4579 6, /* CONF_HW_RXTX_RATE_MCS6 */
4580 5, /* CONF_HW_RXTX_RATE_MCS5 */
4581 4, /* CONF_HW_RXTX_RATE_MCS4 */
4582 3, /* CONF_HW_RXTX_RATE_MCS3 */
4583 2, /* CONF_HW_RXTX_RATE_MCS2 */
4584 1, /* CONF_HW_RXTX_RATE_MCS1 */
4585 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004586
4587 7, /* CONF_HW_RXTX_RATE_54 */
4588 6, /* CONF_HW_RXTX_RATE_48 */
4589 5, /* CONF_HW_RXTX_RATE_36 */
4590 4, /* CONF_HW_RXTX_RATE_24 */
4591
4592 /* TI-specific rate */
4593 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4594
4595 3, /* CONF_HW_RXTX_RATE_18 */
4596 2, /* CONF_HW_RXTX_RATE_12 */
4597 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4598 1, /* CONF_HW_RXTX_RATE_9 */
4599 0, /* CONF_HW_RXTX_RATE_6 */
4600 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4601 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4602 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4603};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004604
4605static struct ieee80211_supported_band wl1271_band_5ghz = {
4606 .channels = wl1271_channels_5ghz,
4607 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4608 .bitrates = wl1271_rates_5ghz,
4609 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004610 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004611};
4612
Tobias Klausera0ea9492010-05-20 10:38:11 +02004613static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004614 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4615 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4616};
4617
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004618static const struct ieee80211_ops wl1271_ops = {
4619 .start = wl1271_op_start,
4620 .stop = wl1271_op_stop,
4621 .add_interface = wl1271_op_add_interface,
4622 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004623 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004624#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004625 .suspend = wl1271_op_suspend,
4626 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004627#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004628 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004629 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004630 .configure_filter = wl1271_op_configure_filter,
4631 .tx = wl1271_op_tx,
4632 .set_key = wl1271_op_set_key,
4633 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004634 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004635 .sched_scan_start = wl1271_op_sched_scan_start,
4636 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004637 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004638 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004639 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004640 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004641 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004642 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004643 .sta_add = wl1271_op_sta_add,
4644 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004645 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004646 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004647 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004648 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004649 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004650};
4651
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004652
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004653u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004654{
4655 u8 idx;
4656
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004657 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004658
4659 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4660 wl1271_error("Illegal RX rate from HW: %d", rate);
4661 return 0;
4662 }
4663
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004664 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004665 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4666 wl1271_error("Unsupported RX rate from HW: %d", rate);
4667 return 0;
4668 }
4669
4670 return idx;
4671}
4672
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004673static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4674 struct device_attribute *attr,
4675 char *buf)
4676{
4677 struct wl1271 *wl = dev_get_drvdata(dev);
4678 ssize_t len;
4679
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004680 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004681
4682 mutex_lock(&wl->mutex);
4683 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4684 wl->sg_enabled);
4685 mutex_unlock(&wl->mutex);
4686
4687 return len;
4688
4689}
4690
4691static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4692 struct device_attribute *attr,
4693 const char *buf, size_t count)
4694{
4695 struct wl1271 *wl = dev_get_drvdata(dev);
4696 unsigned long res;
4697 int ret;
4698
Luciano Coelho6277ed62011-04-01 17:49:54 +03004699 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004700 if (ret < 0) {
4701 wl1271_warning("incorrect value written to bt_coex_mode");
4702 return count;
4703 }
4704
4705 mutex_lock(&wl->mutex);
4706
4707 res = !!res;
4708
4709 if (res == wl->sg_enabled)
4710 goto out;
4711
4712 wl->sg_enabled = res;
4713
4714 if (wl->state == WL1271_STATE_OFF)
4715 goto out;
4716
Ido Yariva6208652011-03-01 15:14:41 +02004717 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004718 if (ret < 0)
4719 goto out;
4720
4721 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4722 wl1271_ps_elp_sleep(wl);
4723
4724 out:
4725 mutex_unlock(&wl->mutex);
4726 return count;
4727}
4728
4729static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4730 wl1271_sysfs_show_bt_coex_state,
4731 wl1271_sysfs_store_bt_coex_state);
4732
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004733static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4734 struct device_attribute *attr,
4735 char *buf)
4736{
4737 struct wl1271 *wl = dev_get_drvdata(dev);
4738 ssize_t len;
4739
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004740 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004741
4742 mutex_lock(&wl->mutex);
4743 if (wl->hw_pg_ver >= 0)
4744 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4745 else
4746 len = snprintf(buf, len, "n/a\n");
4747 mutex_unlock(&wl->mutex);
4748
4749 return len;
4750}
4751
Gery Kahn6f07b722011-07-18 14:21:49 +03004752static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004753 wl1271_sysfs_show_hw_pg_ver, NULL);
4754
Ido Yariv95dac04f2011-06-06 14:57:06 +03004755static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4756 struct bin_attribute *bin_attr,
4757 char *buffer, loff_t pos, size_t count)
4758{
4759 struct device *dev = container_of(kobj, struct device, kobj);
4760 struct wl1271 *wl = dev_get_drvdata(dev);
4761 ssize_t len;
4762 int ret;
4763
4764 ret = mutex_lock_interruptible(&wl->mutex);
4765 if (ret < 0)
4766 return -ERESTARTSYS;
4767
4768 /* Let only one thread read the log at a time, blocking others */
4769 while (wl->fwlog_size == 0) {
4770 DEFINE_WAIT(wait);
4771
4772 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4773 &wait,
4774 TASK_INTERRUPTIBLE);
4775
4776 if (wl->fwlog_size != 0) {
4777 finish_wait(&wl->fwlog_waitq, &wait);
4778 break;
4779 }
4780
4781 mutex_unlock(&wl->mutex);
4782
4783 schedule();
4784 finish_wait(&wl->fwlog_waitq, &wait);
4785
4786 if (signal_pending(current))
4787 return -ERESTARTSYS;
4788
4789 ret = mutex_lock_interruptible(&wl->mutex);
4790 if (ret < 0)
4791 return -ERESTARTSYS;
4792 }
4793
4794 /* Check if the fwlog is still valid */
4795 if (wl->fwlog_size < 0) {
4796 mutex_unlock(&wl->mutex);
4797 return 0;
4798 }
4799
4800 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4801 len = min(count, (size_t)wl->fwlog_size);
4802 wl->fwlog_size -= len;
4803 memcpy(buffer, wl->fwlog, len);
4804
4805 /* Make room for new messages */
4806 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4807
4808 mutex_unlock(&wl->mutex);
4809
4810 return len;
4811}
4812
4813static struct bin_attribute fwlog_attr = {
4814 .attr = {.name = "fwlog", .mode = S_IRUSR},
4815 .read = wl1271_sysfs_read_fwlog,
4816};
4817
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004818static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004819{
4820 int ret;
4821
4822 if (wl->mac80211_registered)
4823 return 0;
4824
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004825 ret = wl1271_fetch_nvs(wl);
4826 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004827 /* NOTE: The wl->nvs->nvs element must be first, in
4828 * order to simplify the casting, we assume it is at
4829 * the beginning of the wl->nvs structure.
4830 */
4831 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004832
4833 wl->mac_addr[0] = nvs_ptr[11];
4834 wl->mac_addr[1] = nvs_ptr[10];
4835 wl->mac_addr[2] = nvs_ptr[6];
4836 wl->mac_addr[3] = nvs_ptr[5];
4837 wl->mac_addr[4] = nvs_ptr[4];
4838 wl->mac_addr[5] = nvs_ptr[3];
4839 }
4840
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004841 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4842
4843 ret = ieee80211_register_hw(wl->hw);
4844 if (ret < 0) {
4845 wl1271_error("unable to register mac80211 hw: %d", ret);
4846 return ret;
4847 }
4848
4849 wl->mac80211_registered = true;
4850
Eliad Pellerd60080a2010-11-24 12:53:16 +02004851 wl1271_debugfs_init(wl);
4852
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004853 register_netdevice_notifier(&wl1271_dev_notifier);
4854
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004855 wl1271_notice("loaded");
4856
4857 return 0;
4858}
4859
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004860static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004861{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004862 if (wl->state == WL1271_STATE_PLT)
4863 __wl1271_plt_stop(wl);
4864
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004865 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004866 ieee80211_unregister_hw(wl->hw);
4867 wl->mac80211_registered = false;
4868
4869}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004870
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004871static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004872{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004873 static const u32 cipher_suites[] = {
4874 WLAN_CIPHER_SUITE_WEP40,
4875 WLAN_CIPHER_SUITE_WEP104,
4876 WLAN_CIPHER_SUITE_TKIP,
4877 WLAN_CIPHER_SUITE_CCMP,
4878 WL1271_CIPHER_SUITE_GEM,
4879 };
4880
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004881 /* The tx descriptor buffer and the TKIP space. */
4882 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4883 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004884
4885 /* unit us */
4886 /* FIXME: find a proper value */
4887 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004888 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004889
4890 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004891 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004892 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004893 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004894 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004895 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004896 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004897 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004898 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004899 IEEE80211_HW_AP_LINK_PS |
4900 IEEE80211_HW_AMPDU_AGGREGATION |
4901 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004902
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004903 wl->hw->wiphy->cipher_suites = cipher_suites;
4904 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4905
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004906 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004907 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4908 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004909 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004910 wl->hw->wiphy->max_sched_scan_ssids = 16;
4911 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004912 /*
4913 * Maximum length of elements in scanning probe request templates
4914 * should be the maximum length possible for a template, without
4915 * the IEEE80211 header of the template
4916 */
Eliad Peller154037d2011-08-14 13:17:12 +03004917 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004918 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004919
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004920 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4921 sizeof(struct ieee80211_header);
4922
Eliad Peller1ec23f72011-08-25 14:26:54 +03004923 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4924
Luciano Coelho4a31c112011-03-21 23:16:14 +02004925 /* make sure all our channels fit in the scanned_ch bitmask */
4926 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4927 ARRAY_SIZE(wl1271_channels_5ghz) >
4928 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004929 /*
4930 * We keep local copies of the band structs because we need to
4931 * modify them on a per-device basis.
4932 */
4933 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4934 sizeof(wl1271_band_2ghz));
4935 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4936 sizeof(wl1271_band_5ghz));
4937
4938 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4939 &wl->bands[IEEE80211_BAND_2GHZ];
4940 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4941 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004942
Kalle Valo12bd8942010-03-18 12:26:33 +02004943 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004944 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004945
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004946 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4947
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02004948 /* the FW answers probe-requests in AP-mode */
4949 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
4950 wl->hw->wiphy->probe_resp_offload =
4951 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
4952 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
4953 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
4954
Felipe Balbia390e852011-10-06 10:07:44 +03004955 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004956
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004957 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004958 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004959
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004960 wl->hw->max_rx_aggregation_subframes = 8;
4961
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004962 return 0;
4963}
4964
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004965#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004966
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004967static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004968{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004969 struct ieee80211_hw *hw;
4970 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004971 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004972 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004973
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004974 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004975
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004976 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4977 if (!hw) {
4978 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004979 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004980 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004981 }
4982
4983 wl = hw->priv;
4984 memset(wl, 0, sizeof(*wl));
4985
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004986 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02004987 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004988
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004989 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004990
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004991 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004992 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004993 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4994
Ido Yariva6208652011-03-01 15:14:41 +02004995 skb_queue_head_init(&wl->deferred_rx_queue);
4996 skb_queue_head_init(&wl->deferred_tx_queue);
4997
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004998 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02004999 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005000 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5001 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5002 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005003
Eliad Peller92ef8962011-06-07 12:50:46 +03005004 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5005 if (!wl->freezable_wq) {
5006 ret = -ENOMEM;
5007 goto err_hw;
5008 }
5009
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005010 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005011 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005012 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005013 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005014 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005015 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005016 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005017 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005018 wl->ap_ps_map = 0;
5019 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005020 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005021 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005022 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005023 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005024 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005025 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005026 wl->fwlog_size = 0;
5027 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005028
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005029 /* The system link is always allocated */
5030 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5031
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005032 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005033 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005034 wl->tx_frames[i] = NULL;
5035
5036 spin_lock_init(&wl->wl_lock);
5037
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005038 wl->state = WL1271_STATE_OFF;
5039 mutex_init(&wl->mutex);
5040
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005041 /* Apply default driver configuration. */
5042 wl1271_conf_init(wl);
5043
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005044 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5045 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5046 if (!wl->aggr_buf) {
5047 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005048 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005049 }
5050
Ido Yariv990f5de2011-03-31 10:06:59 +02005051 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5052 if (!wl->dummy_packet) {
5053 ret = -ENOMEM;
5054 goto err_aggr;
5055 }
5056
Ido Yariv95dac04f2011-06-06 14:57:06 +03005057 /* Allocate one page for the FW log */
5058 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5059 if (!wl->fwlog) {
5060 ret = -ENOMEM;
5061 goto err_dummy_packet;
5062 }
5063
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005064 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005065
Ido Yariv990f5de2011-03-31 10:06:59 +02005066err_dummy_packet:
5067 dev_kfree_skb(wl->dummy_packet);
5068
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005069err_aggr:
5070 free_pages((unsigned long)wl->aggr_buf, order);
5071
Eliad Peller92ef8962011-06-07 12:50:46 +03005072err_wq:
5073 destroy_workqueue(wl->freezable_wq);
5074
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005075err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005076 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005077 ieee80211_free_hw(hw);
5078
5079err_hw_alloc:
5080
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005081 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005082}
5083
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005084static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005085{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005086 /* Unblock any fwlog readers */
5087 mutex_lock(&wl->mutex);
5088 wl->fwlog_size = -1;
5089 wake_up_interruptible_all(&wl->fwlog_waitq);
5090 mutex_unlock(&wl->mutex);
5091
Felipe Balbif79f8902011-10-06 13:05:25 +03005092 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005093
Felipe Balbif79f8902011-10-06 13:05:25 +03005094 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005095
Felipe Balbif79f8902011-10-06 13:05:25 +03005096 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005097 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005098 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005099 free_pages((unsigned long)wl->aggr_buf,
5100 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005101
5102 wl1271_debugfs_exit(wl);
5103
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005104 vfree(wl->fw);
5105 wl->fw = NULL;
5106 kfree(wl->nvs);
5107 wl->nvs = NULL;
5108
5109 kfree(wl->fw_status);
5110 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005111 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005112
5113 ieee80211_free_hw(wl->hw);
5114
5115 return 0;
5116}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005117
Felipe Balbia390e852011-10-06 10:07:44 +03005118static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5119{
5120 struct wl1271 *wl = cookie;
5121 unsigned long flags;
5122
5123 wl1271_debug(DEBUG_IRQ, "IRQ");
5124
5125 /* complete the ELP completion */
5126 spin_lock_irqsave(&wl->wl_lock, flags);
5127 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5128 if (wl->elp_compl) {
5129 complete(wl->elp_compl);
5130 wl->elp_compl = NULL;
5131 }
5132
5133 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5134 /* don't enqueue a work right now. mark it as pending */
5135 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5136 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5137 disable_irq_nosync(wl->irq);
5138 pm_wakeup_event(wl->dev, 0);
5139 spin_unlock_irqrestore(&wl->wl_lock, flags);
5140 return IRQ_HANDLED;
5141 }
5142 spin_unlock_irqrestore(&wl->wl_lock, flags);
5143
5144 return IRQ_WAKE_THREAD;
5145}
5146
Felipe Balbice2a2172011-10-05 14:12:55 +03005147static int __devinit wl12xx_probe(struct platform_device *pdev)
5148{
Felipe Balbia390e852011-10-06 10:07:44 +03005149 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5150 struct ieee80211_hw *hw;
5151 struct wl1271 *wl;
5152 unsigned long irqflags;
5153 int ret = -ENODEV;
5154
5155 hw = wl1271_alloc_hw();
5156 if (IS_ERR(hw)) {
5157 wl1271_error("can't allocate hw");
5158 ret = PTR_ERR(hw);
5159 goto out;
5160 }
5161
5162 wl = hw->priv;
5163 wl->irq = platform_get_irq(pdev, 0);
5164 wl->ref_clock = pdata->board_ref_clock;
5165 wl->tcxo_clock = pdata->board_tcxo_clock;
5166 wl->platform_quirks = pdata->platform_quirks;
5167 wl->set_power = pdata->set_power;
5168 wl->dev = &pdev->dev;
5169 wl->if_ops = pdata->ops;
5170
5171 platform_set_drvdata(pdev, wl);
5172
5173 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5174 irqflags = IRQF_TRIGGER_RISING;
5175 else
5176 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5177
5178 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5179 irqflags,
5180 pdev->name, wl);
5181 if (ret < 0) {
5182 wl1271_error("request_irq() failed: %d", ret);
5183 goto out_free_hw;
5184 }
5185
5186 ret = enable_irq_wake(wl->irq);
5187 if (!ret) {
5188 wl->irq_wake_enabled = true;
5189 device_init_wakeup(wl->dev, 1);
5190 if (pdata->pwr_in_suspend)
5191 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5192
5193 }
5194 disable_irq(wl->irq);
5195
5196 ret = wl1271_init_ieee80211(wl);
5197 if (ret)
5198 goto out_irq;
5199
5200 ret = wl1271_register_hw(wl);
5201 if (ret)
5202 goto out_irq;
5203
Felipe Balbif79f8902011-10-06 13:05:25 +03005204 /* Create sysfs file to control bt coex state */
5205 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5206 if (ret < 0) {
5207 wl1271_error("failed to create sysfs file bt_coex_state");
5208 goto out_irq;
5209 }
5210
5211 /* Create sysfs file to get HW PG version */
5212 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5213 if (ret < 0) {
5214 wl1271_error("failed to create sysfs file hw_pg_ver");
5215 goto out_bt_coex_state;
5216 }
5217
5218 /* Create sysfs file for the FW log */
5219 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5220 if (ret < 0) {
5221 wl1271_error("failed to create sysfs file fwlog");
5222 goto out_hw_pg_ver;
5223 }
5224
Felipe Balbice2a2172011-10-05 14:12:55 +03005225 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005226
Felipe Balbif79f8902011-10-06 13:05:25 +03005227out_hw_pg_ver:
5228 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5229
5230out_bt_coex_state:
5231 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5232
Felipe Balbia390e852011-10-06 10:07:44 +03005233out_irq:
5234 free_irq(wl->irq, wl);
5235
5236out_free_hw:
5237 wl1271_free_hw(wl);
5238
5239out:
5240 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005241}
5242
5243static int __devexit wl12xx_remove(struct platform_device *pdev)
5244{
Felipe Balbia390e852011-10-06 10:07:44 +03005245 struct wl1271 *wl = platform_get_drvdata(pdev);
5246
5247 if (wl->irq_wake_enabled) {
5248 device_init_wakeup(wl->dev, 0);
5249 disable_irq_wake(wl->irq);
5250 }
5251 wl1271_unregister_hw(wl);
5252 free_irq(wl->irq, wl);
5253 wl1271_free_hw(wl);
5254
Felipe Balbice2a2172011-10-05 14:12:55 +03005255 return 0;
5256}
5257
5258static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005259 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005260 { } /* Terminating Entry */
5261};
5262MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5263
5264static struct platform_driver wl12xx_driver = {
5265 .probe = wl12xx_probe,
5266 .remove = __devexit_p(wl12xx_remove),
5267 .id_table = wl12xx_id_table,
5268 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005269 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005270 .owner = THIS_MODULE,
5271 }
5272};
5273
5274static int __init wl12xx_init(void)
5275{
5276 return platform_driver_register(&wl12xx_driver);
5277}
5278module_init(wl12xx_init);
5279
5280static void __exit wl12xx_exit(void)
5281{
5282 platform_driver_unregister(&wl12xx_driver);
5283}
5284module_exit(wl12xx_exit);
5285
Guy Eilam491bbd62011-01-12 10:33:29 +01005286u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005287EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005288module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005289MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5290
Ido Yariv95dac04f2011-06-06 14:57:06 +03005291module_param_named(fwlog, fwlog_param, charp, 0);
5292MODULE_PARM_DESC(keymap,
5293 "FW logger options: continuous, ondemand, dbgpins or disable");
5294
Eliad Peller2a5bff02011-08-25 18:10:59 +03005295module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5296MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5297
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005298MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005299MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005300MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");