blob: 8ff1bf5be0134db9594cc418b9d560aa29e537db [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{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200644 struct conf_tx_ac_category *conf_ac;
645 struct conf_tx_tid *conf_tid;
646 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300647
Shahar Levi49d750ca2011-03-06 16:32:09 +0200648 if (wl->chip.id == CHIP_ID_1283_PG20)
649 ret = wl128x_cmd_general_parms(wl);
650 else
651 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200652 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200653 return ret;
654
Shahar Levi49d750ca2011-03-06 16:32:09 +0200655 if (wl->chip.id == CHIP_ID_1283_PG20)
656 ret = wl128x_cmd_radio_parms(wl);
657 else
658 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200659 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200660 return ret;
661
Shahar Levi49d750ca2011-03-06 16:32:09 +0200662 if (wl->chip.id != CHIP_ID_1283_PG20) {
663 ret = wl1271_cmd_ext_radio_parms(wl);
664 if (ret < 0)
665 return ret;
666 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200667 if (ret < 0)
668 return ret;
669
Shahar Levi48a61472011-03-06 16:32:08 +0200670 /* Chip-specific initializations */
671 ret = wl1271_chip_specific_init(wl);
672 if (ret < 0)
673 return ret;
674
Eliad Peller92c77c72011-10-05 11:55:40 +0200675 ret = wl1271_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200676 if (ret < 0)
677 return ret;
678
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679 ret = wl1271_acx_init_mem_config(wl);
680 if (ret < 0)
681 return ret;
682
Luciano Coelho12419cc2010-02-18 13:25:44 +0200683 /* PHY layer config */
684 ret = wl1271_init_phy_config(wl);
685 if (ret < 0)
686 goto out_free_memmap;
687
688 ret = wl1271_acx_dco_itrim_params(wl);
689 if (ret < 0)
690 goto out_free_memmap;
691
692 /* Initialize connection monitoring thresholds */
Eliad Peller0603d892011-10-05 11:55:51 +0200693 ret = wl1271_acx_conn_monit_params(wl, NULL, false); /* TODO: fix */
Luciano Coelho12419cc2010-02-18 13:25:44 +0200694 if (ret < 0)
695 goto out_free_memmap;
696
697 /* Bluetooth WLAN coexistence */
698 ret = wl1271_init_pta(wl);
699 if (ret < 0)
700 goto out_free_memmap;
701
Shahar Leviff868432011-04-11 15:41:46 +0300702 /* FM WLAN coexistence */
703 ret = wl1271_acx_fm_coex(wl);
704 if (ret < 0)
705 goto out_free_memmap;
706
Luciano Coelho12419cc2010-02-18 13:25:44 +0200707 /* Energy detection */
708 ret = wl1271_init_energy_detection(wl);
709 if (ret < 0)
710 goto out_free_memmap;
711
Eliad Peller7f0979882011-08-14 13:17:06 +0300712 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600713 if (ret < 0)
714 goto out_free_memmap;
715
Luciano Coelho12419cc2010-02-18 13:25:44 +0200716 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100717 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200718 if (ret < 0)
719 goto out_free_memmap;
720
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200721 /* Default TID/AC configuration */
722 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200723 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200724 conf_ac = &wl->conf.tx.ac_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200725 /* TODO: fix */
726 ret = wl1271_acx_ac_cfg(wl, NULL, conf_ac->ac, conf_ac->cw_min,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200727 conf_ac->cw_max, conf_ac->aifsn,
728 conf_ac->tx_op_limit);
729 if (ret < 0)
730 goto out_free_memmap;
731
Luciano Coelho12419cc2010-02-18 13:25:44 +0200732 conf_tid = &wl->conf.tx.tid_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200733 /* TODO: fix */
734 ret = wl1271_acx_tid_cfg(wl, NULL, conf_tid->queue_id,
Luciano Coelho12419cc2010-02-18 13:25:44 +0200735 conf_tid->channel_type,
736 conf_tid->tsid,
737 conf_tid->ps_scheme,
738 conf_tid->ack_policy,
739 conf_tid->apsd_conf[0],
740 conf_tid->apsd_conf[1]);
741 if (ret < 0)
742 goto out_free_memmap;
743 }
744
Luciano Coelho12419cc2010-02-18 13:25:44 +0200745 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200746 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300747 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200748 goto out_free_memmap;
749
750 /* Configure for CAM power saving (ie. always active) */
751 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
752 if (ret < 0)
753 goto out_free_memmap;
754
755 /* configure PM */
756 ret = wl1271_acx_pm_config(wl);
757 if (ret < 0)
758 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300759
760 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200761
762 out_free_memmap:
763 kfree(wl->target_mem_map);
764 wl->target_mem_map = NULL;
765
766 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767}
768
Eliad Peller6e8cd332011-10-10 10:13:13 +0200769static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
770 struct wl12xx_vif *wlvif,
771 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200772{
Arik Nemtsovda032092011-08-25 12:43:15 +0300773 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200774
Arik Nemtsovb622d992011-02-23 00:22:31 +0200775 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300776 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200777
778 /*
779 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300780 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200781 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300782 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200783 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200784
Arik Nemtsovda032092011-08-25 12:43:15 +0300785 /*
786 * Start high-level PS if the STA is asleep with enough blocks in FW.
787 * Make an exception if this is the only connected station. In this
788 * case FW-memory congestion is not a problem.
789 */
790 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200791 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200792}
793
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300794static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200795 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300796 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200797{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200798 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200799 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300800 u8 hlid, cnt;
801
802 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200803
804 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
805 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
806 wl1271_debug(DEBUG_PSM,
807 "link ps prev 0x%x cur 0x%x changed 0x%x",
808 wl->ap_fw_ps_map, cur_fw_ps_map,
809 wl->ap_fw_ps_map ^ cur_fw_ps_map);
810
811 wl->ap_fw_ps_map = cur_fw_ps_map;
812 }
813
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200814 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
815 lnk = &wl->links[hlid];
816 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200817
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200818 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
819 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200820
Eliad Peller6e8cd332011-10-10 10:13:13 +0200821 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
822 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200823 }
824}
825
Eliad Peller4d56ad92011-08-14 13:17:05 +0300826static void wl12xx_fw_status(struct wl1271 *wl,
827 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200829 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200830 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200831 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300832 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300833 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834
Eliad Peller4d56ad92011-08-14 13:17:05 +0300835 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200836
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300837 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
838 "drv_rx_counter = %d, tx_results_counter = %d)",
839 status->intr,
840 status->fw_rx_counter,
841 status->drv_rx_counter,
842 status->tx_results_counter);
843
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300844 for (i = 0; i < NUM_TX_QUEUES; i++) {
845 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300846 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300847 (status->tx_released_pkts[i] -
848 wl->tx_pkts_freed[i]) & 0xff;
849
850 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
851 }
852
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300853 /* prevent wrap-around in total blocks counter */
854 if (likely(wl->tx_blocks_freed <=
855 le32_to_cpu(status->total_released_blks)))
856 freed_blocks = le32_to_cpu(status->total_released_blks) -
857 wl->tx_blocks_freed;
858 else
859 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
860 le32_to_cpu(status->total_released_blks);
861
Eliad Peller4d56ad92011-08-14 13:17:05 +0300862 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200863
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300864 wl->tx_allocated_blocks -= freed_blocks;
865
Eliad Peller4d56ad92011-08-14 13:17:05 +0300866 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200867
Eliad Peller4d56ad92011-08-14 13:17:05 +0300868 /*
869 * The FW might change the total number of TX memblocks before
870 * we get a notification about blocks being released. Thus, the
871 * available blocks calculation might yield a temporary result
872 * which is lower than the actual available blocks. Keeping in
873 * mind that only blocks that were allocated can be moved from
874 * TX to RX, tx_blocks_available should never decrease here.
875 */
876 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
877 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878
Ido Yariva5225502010-10-12 14:49:10 +0200879 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200880 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200881 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300882
Eliad Peller4d56ad92011-08-14 13:17:05 +0300883 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200884 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200885 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200886 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300887
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300888 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200889 getnstimeofday(&ts);
890 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
891 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300892}
893
Ido Yariva6208652011-03-01 15:14:41 +0200894static void wl1271_flush_deferred_work(struct wl1271 *wl)
895{
896 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200897
Ido Yariva6208652011-03-01 15:14:41 +0200898 /* Pass all received frames to the network stack */
899 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
900 ieee80211_rx_ni(wl->hw, skb);
901
902 /* Return sent skbs to the network stack */
903 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300904 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200905}
906
907static void wl1271_netstack_work(struct work_struct *work)
908{
909 struct wl1271 *wl =
910 container_of(work, struct wl1271, netstack_work);
911
912 do {
913 wl1271_flush_deferred_work(wl);
914 } while (skb_queue_len(&wl->deferred_rx_queue));
915}
916
917#define WL1271_IRQ_MAX_LOOPS 256
918
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300919static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300920{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300921 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300922 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200923 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200924 struct wl1271 *wl = (struct wl1271 *)cookie;
925 bool done = false;
926 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200927 unsigned long flags;
928
929 /* TX might be handled here, avoid redundant work */
930 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
931 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932
Ido Yariv341b7cd2011-03-31 10:07:01 +0200933 /*
934 * In case edge triggered interrupt must be used, we cannot iterate
935 * more than once without introducing race conditions with the hardirq.
936 */
937 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
938 loopcount = 1;
939
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300940 mutex_lock(&wl->mutex);
941
942 wl1271_debug(DEBUG_IRQ, "IRQ work");
943
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200944 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945 goto out;
946
Ido Yariva6208652011-03-01 15:14:41 +0200947 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948 if (ret < 0)
949 goto out;
950
Ido Yariva6208652011-03-01 15:14:41 +0200951 while (!done && loopcount--) {
952 /*
953 * In order to avoid a race with the hardirq, clear the flag
954 * before acknowledging the chip. Since the mutex is held,
955 * wl1271_ps_elp_wakeup cannot be called concurrently.
956 */
957 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
958 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200959
Eliad Peller4d56ad92011-08-14 13:17:05 +0300960 wl12xx_fw_status(wl, wl->fw_status);
961 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200962 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200963 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200964 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200965 continue;
966 }
967
Eliad Pellerccc83b02010-10-27 14:09:57 +0200968 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
969 wl1271_error("watchdog interrupt received! "
970 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300971 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200972
973 /* restarting the chip. ignore any other interrupt. */
974 goto out;
975 }
976
Ido Yariva6208652011-03-01 15:14:41 +0200977 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200978 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
979
Eliad Peller4d56ad92011-08-14 13:17:05 +0300980 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200981
Ido Yariva5225502010-10-12 14:49:10 +0200982 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200983 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200984 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300985 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200986 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200987 /*
988 * In order to avoid starvation of the TX path,
989 * call the work function directly.
990 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200991 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200992 } else {
993 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200994 }
995
Ido Yariv8aad2462011-03-01 15:14:38 +0200996 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300997 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200998 (wl->tx_results_count & 0xff))
999 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001000
1001 /* Make sure the deferred queues don't get too long */
1002 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1003 skb_queue_len(&wl->deferred_rx_queue);
1004 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1005 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001006 }
1007
1008 if (intr & WL1271_ACX_INTR_EVENT_A) {
1009 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1010 wl1271_event_handle(wl, 0);
1011 }
1012
1013 if (intr & WL1271_ACX_INTR_EVENT_B) {
1014 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1015 wl1271_event_handle(wl, 1);
1016 }
1017
1018 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1019 wl1271_debug(DEBUG_IRQ,
1020 "WL1271_ACX_INTR_INIT_COMPLETE");
1021
1022 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1023 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024 }
1025
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026 wl1271_ps_elp_sleep(wl);
1027
1028out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001029 spin_lock_irqsave(&wl->wl_lock, flags);
1030 /* In case TX was not handled here, queue TX work */
1031 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1032 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001033 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001034 ieee80211_queue_work(wl->hw, &wl->tx_work);
1035 spin_unlock_irqrestore(&wl->wl_lock, flags);
1036
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001038
1039 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040}
1041
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042static int wl1271_fetch_firmware(struct wl1271 *wl)
1043{
1044 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001045 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046 int ret;
1047
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001048 if (wl->chip.id == CHIP_ID_1283_PG20)
1049 fw_name = WL128X_FW_NAME;
1050 else
1051 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001052
1053 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1054
Felipe Balbia390e852011-10-06 10:07:44 +03001055 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056
1057 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001058 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001059 return ret;
1060 }
1061
1062 if (fw->size % 4) {
1063 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1064 fw->size);
1065 ret = -EILSEQ;
1066 goto out;
1067 }
1068
Arik Nemtsov166d5042010-10-16 21:44:57 +02001069 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001070 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001071 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001072
1073 if (!wl->fw) {
1074 wl1271_error("could not allocate memory for the firmware");
1075 ret = -ENOMEM;
1076 goto out;
1077 }
1078
1079 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080 ret = 0;
1081
1082out:
1083 release_firmware(fw);
1084
1085 return ret;
1086}
1087
1088static int wl1271_fetch_nvs(struct wl1271 *wl)
1089{
1090 const struct firmware *fw;
1091 int ret;
1092
Felipe Balbia390e852011-10-06 10:07:44 +03001093 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001094
1095 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001096 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
1097 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001098 return ret;
1099 }
1100
Shahar Levibc765bf2011-03-06 16:32:10 +02001101 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001102
1103 if (!wl->nvs) {
1104 wl1271_error("could not allocate memory for the nvs file");
1105 ret = -ENOMEM;
1106 goto out;
1107 }
1108
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001109 wl->nvs_len = fw->size;
1110
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111out:
1112 release_firmware(fw);
1113
1114 return ret;
1115}
1116
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001117void wl12xx_queue_recovery_work(struct wl1271 *wl)
1118{
1119 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1120 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1121}
1122
Ido Yariv95dac04f2011-06-06 14:57:06 +03001123size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1124{
1125 size_t len = 0;
1126
1127 /* The FW log is a length-value list, find where the log end */
1128 while (len < maxlen) {
1129 if (memblock[len] == 0)
1130 break;
1131 if (len + memblock[len] + 1 > maxlen)
1132 break;
1133 len += memblock[len] + 1;
1134 }
1135
1136 /* Make sure we have enough room */
1137 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1138
1139 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1140 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1141 wl->fwlog_size += len;
1142
1143 return len;
1144}
1145
1146static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1147{
1148 u32 addr;
1149 u32 first_addr;
1150 u8 *block;
1151
1152 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1153 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1154 (wl->conf.fwlog.mem_blocks == 0))
1155 return;
1156
1157 wl1271_info("Reading FW panic log");
1158
1159 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1160 if (!block)
1161 return;
1162
1163 /*
1164 * Make sure the chip is awake and the logger isn't active.
1165 * This might fail if the firmware hanged.
1166 */
1167 if (!wl1271_ps_elp_wakeup(wl))
1168 wl12xx_cmd_stop_fwlog(wl);
1169
1170 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001171 wl12xx_fw_status(wl, wl->fw_status);
1172 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001173 if (!first_addr)
1174 goto out;
1175
1176 /* Traverse the memory blocks linked list */
1177 addr = first_addr;
1178 do {
1179 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1180 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1181 false);
1182
1183 /*
1184 * Memory blocks are linked to one another. The first 4 bytes
1185 * of each memory block hold the hardware address of the next
1186 * one. The last memory block points to the first one.
1187 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001188 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001189 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1190 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1191 break;
1192 } while (addr && (addr != first_addr));
1193
1194 wake_up_interruptible(&wl->fwlog_waitq);
1195
1196out:
1197 kfree(block);
1198}
1199
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001200static void wl1271_recovery_work(struct work_struct *work)
1201{
1202 struct wl1271 *wl =
1203 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001204 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001205 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001206
1207 mutex_lock(&wl->mutex);
1208
1209 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001210 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001211
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001212 /* Avoid a recursive recovery */
1213 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1214
Ido Yariv95dac04f2011-06-06 14:57:06 +03001215 wl12xx_read_fwlog_panic(wl);
1216
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001217 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1218 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001219
Eliad Peller2a5bff02011-08-25 18:10:59 +03001220 BUG_ON(bug_on_recovery);
1221
Oz Krakowskib992c682011-06-26 10:36:02 +03001222 /*
1223 * Advance security sequence number to overcome potential progress
1224 * in the firmware during recovery. This doens't hurt if the network is
1225 * not encrypted.
1226 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001227 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001228 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001229 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001230 wlvif->tx_security_seq +=
1231 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1232 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001233
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001234 /* Prevent spurious TX during FW restart */
1235 ieee80211_stop_queues(wl->hw);
1236
Luciano Coelho33c2c062011-05-10 14:46:02 +03001237 if (wl->sched_scanning) {
1238 ieee80211_sched_scan_stopped(wl->hw);
1239 wl->sched_scanning = false;
1240 }
1241
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001242 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001243 while (!list_empty(&wl->wlvif_list)) {
1244 wlvif = list_first_entry(&wl->wlvif_list,
1245 struct wl12xx_vif, list);
1246 vif = wl12xx_wlvif_to_vif(wlvif);
1247 __wl1271_op_remove_interface(wl, vif, false);
1248 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001249 mutex_unlock(&wl->mutex);
1250 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001251
1252 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1253
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001254 ieee80211_restart_hw(wl->hw);
1255
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001256 /*
1257 * Its safe to enable TX now - the queues are stopped after a request
1258 * to restart the HW.
1259 */
1260 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001261 return;
1262out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001263 mutex_unlock(&wl->mutex);
1264}
1265
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001266static void wl1271_fw_wakeup(struct wl1271 *wl)
1267{
1268 u32 elp_reg;
1269
1270 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001271 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001272}
1273
1274static int wl1271_setup(struct wl1271 *wl)
1275{
1276 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1277 if (!wl->fw_status)
1278 return -ENOMEM;
1279
1280 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1281 if (!wl->tx_res_if) {
1282 kfree(wl->fw_status);
1283 return -ENOMEM;
1284 }
1285
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001286 return 0;
1287}
1288
1289static int wl1271_chip_wakeup(struct wl1271 *wl)
1290{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001291 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001292 int ret = 0;
1293
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001294 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001295 ret = wl1271_power_on(wl);
1296 if (ret < 0)
1297 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001298 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001299 wl1271_io_reset(wl);
1300 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301
1302 /* We don't need a real memory partition here, because we only want
1303 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001304 memset(&partition, 0, sizeof(partition));
1305 partition.reg.start = REGISTERS_BASE;
1306 partition.reg.size = REGISTERS_DOWN_SIZE;
1307 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001308
1309 /* ELP module wake up */
1310 wl1271_fw_wakeup(wl);
1311
1312 /* whal_FwCtrl_BootSm() */
1313
1314 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001315 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001316
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001317 /*
1318 * For wl127x based devices we could use the default block
1319 * size (512 bytes), but due to a bug in the sdio driver, we
1320 * need to set it explicitly after the chip is powered on. To
1321 * simplify the code and since the performance impact is
1322 * negligible, we use the same block size for all different
1323 * chip types.
1324 */
1325 if (!wl1271_set_block_size(wl))
1326 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327
1328 switch (wl->chip.id) {
1329 case CHIP_ID_1271_PG10:
1330 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1331 wl->chip.id);
1332
1333 ret = wl1271_setup(wl);
1334 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001335 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001336 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001337 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001338
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339 case CHIP_ID_1271_PG20:
1340 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1341 wl->chip.id);
1342
1343 ret = wl1271_setup(wl);
1344 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001345 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001346 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001348
Shahar Levi0830cee2011-03-06 16:32:20 +02001349 case CHIP_ID_1283_PG20:
1350 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1351 wl->chip.id);
1352
1353 ret = wl1271_setup(wl);
1354 if (ret < 0)
1355 goto out;
1356 break;
1357 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001358 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001359 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001361 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362 }
1363
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001364 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001365 ret = wl1271_fetch_firmware(wl);
1366 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001367 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368 }
1369
1370 /* No NVS from netlink, try to get it from the filesystem */
1371 if (wl->nvs == NULL) {
1372 ret = wl1271_fetch_nvs(wl);
1373 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001374 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001375 }
1376
1377out:
1378 return ret;
1379}
1380
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001381int wl1271_plt_start(struct wl1271 *wl)
1382{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001383 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001384 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385 int ret;
1386
1387 mutex_lock(&wl->mutex);
1388
1389 wl1271_notice("power up");
1390
1391 if (wl->state != WL1271_STATE_OFF) {
1392 wl1271_error("cannot go into PLT state because not "
1393 "in off state: %d", wl->state);
1394 ret = -EBUSY;
1395 goto out;
1396 }
1397
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001398 while (retries) {
1399 retries--;
1400 ret = wl1271_chip_wakeup(wl);
1401 if (ret < 0)
1402 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001403
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001404 ret = wl1271_boot(wl);
1405 if (ret < 0)
1406 goto power_off;
1407
1408 ret = wl1271_plt_init(wl);
1409 if (ret < 0)
1410 goto irq_disable;
1411
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001412 wl->state = WL1271_STATE_PLT;
1413 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001414 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001415
Gery Kahn6f07b722011-07-18 14:21:49 +03001416 /* update hw/fw version info in wiphy struct */
1417 wiphy->hw_version = wl->chip.id;
1418 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1419 sizeof(wiphy->fw_version));
1420
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001421 goto out;
1422
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001423irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001424 mutex_unlock(&wl->mutex);
1425 /* Unlocking the mutex in the middle of handling is
1426 inherently unsafe. In this case we deem it safe to do,
1427 because we need to let any possibly pending IRQ out of
1428 the system (and while we are WL1271_STATE_OFF the IRQ
1429 work function will not do anything.) Also, any other
1430 possible concurrent operations will fail due to the
1431 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001432 wl1271_disable_interrupts(wl);
1433 wl1271_flush_deferred_work(wl);
1434 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001435 mutex_lock(&wl->mutex);
1436power_off:
1437 wl1271_power_off(wl);
1438 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001439
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001440 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1441 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001442out:
1443 mutex_unlock(&wl->mutex);
1444
1445 return ret;
1446}
1447
Luciano Coelho4623ec72011-03-21 19:26:41 +02001448static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001449{
1450 int ret = 0;
1451
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001452 wl1271_notice("power down");
1453
1454 if (wl->state != WL1271_STATE_PLT) {
1455 wl1271_error("cannot power down because not in PLT "
1456 "state: %d", wl->state);
1457 ret = -EBUSY;
1458 goto out;
1459 }
1460
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001461 wl1271_power_off(wl);
1462
1463 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001464 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001466 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001467 wl1271_disable_interrupts(wl);
1468 wl1271_flush_deferred_work(wl);
1469 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001470 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001471 mutex_lock(&wl->mutex);
1472out:
1473 return ret;
1474}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001475
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001476int wl1271_plt_stop(struct wl1271 *wl)
1477{
1478 int ret;
1479
1480 mutex_lock(&wl->mutex);
1481 ret = __wl1271_plt_stop(wl);
1482 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001483 return ret;
1484}
1485
Johannes Berg7bb45682011-02-24 14:42:06 +01001486static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001487{
1488 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001489 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1490 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001491 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001492 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001493 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001494 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001495
Eliad Peller0f168012011-10-11 13:52:25 +02001496 if (vif)
1497 wlvif = wl12xx_vif_to_data(vif);
1498
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001499 mapping = skb_get_queue_mapping(skb);
1500 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001501
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001502 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001503
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001504 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001505
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001506 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001507 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001508 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001509 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
1510 dev_kfree_skb(skb);
1511 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001512 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001513
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001514 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1515 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1516
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001517 wl->tx_queue_count[q]++;
1518
1519 /*
1520 * The workqueue is slow to process the tx_queue and we need stop
1521 * the queue here, otherwise the queue will get too long.
1522 */
1523 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1524 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1525 ieee80211_stop_queue(wl->hw, mapping);
1526 set_bit(q, &wl->stopped_queues_map);
1527 }
1528
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001529 /*
1530 * The chip specific setup must run before the first TX packet -
1531 * before that, the tx_work will not be initialized!
1532 */
1533
Ido Yarivb07d4032011-03-01 15:14:43 +02001534 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1535 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001536 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001537
Arik Nemtsov04216da2011-08-14 13:17:38 +03001538out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001539 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001540}
1541
Shahar Leviae47c452011-03-06 16:32:14 +02001542int wl1271_tx_dummy_packet(struct wl1271 *wl)
1543{
Ido Yariv990f5de2011-03-31 10:06:59 +02001544 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001545 int q;
1546
1547 /* no need to queue a new dummy packet if one is already pending */
1548 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1549 return 0;
1550
1551 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001552
Ido Yariv990f5de2011-03-31 10:06:59 +02001553 spin_lock_irqsave(&wl->wl_lock, flags);
1554 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001555 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001556 spin_unlock_irqrestore(&wl->wl_lock, flags);
1557
1558 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1559 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001560 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001561
1562 /*
1563 * If the FW TX is busy, TX work will be scheduled by the threaded
1564 * interrupt handler function
1565 */
1566 return 0;
1567}
1568
1569/*
1570 * The size of the dummy packet should be at least 1400 bytes. However, in
1571 * order to minimize the number of bus transactions, aligning it to 512 bytes
1572 * boundaries could be beneficial, performance wise
1573 */
1574#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1575
Luciano Coelhocf27d862011-04-01 21:08:23 +03001576static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001577{
1578 struct sk_buff *skb;
1579 struct ieee80211_hdr_3addr *hdr;
1580 unsigned int dummy_packet_size;
1581
1582 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1583 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1584
1585 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001586 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001587 wl1271_warning("Failed to allocate a dummy packet skb");
1588 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001589 }
1590
1591 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1592
1593 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1594 memset(hdr, 0, sizeof(*hdr));
1595 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001596 IEEE80211_STYPE_NULLFUNC |
1597 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001598
Ido Yariv990f5de2011-03-31 10:06:59 +02001599 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001600
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001601 /* Dummy packets require the TID to be management */
1602 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001603
1604 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001605 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001606 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001607
Ido Yariv990f5de2011-03-31 10:06:59 +02001608 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001609}
1610
Ido Yariv990f5de2011-03-31 10:06:59 +02001611
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001612static struct notifier_block wl1271_dev_notifier = {
1613 .notifier_call = wl1271_dev_notify,
1614};
1615
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001616#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001617static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1618 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001619{
Eliad Pellere85d1622011-06-27 13:06:43 +03001620 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001621
Eliad Peller94390642011-05-13 11:57:13 +03001622 mutex_lock(&wl->mutex);
1623
Eliad Pellerba8447f2011-10-10 10:13:00 +02001624 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001625 goto out_unlock;
1626
Eliad Peller94390642011-05-13 11:57:13 +03001627 ret = wl1271_ps_elp_wakeup(wl);
1628 if (ret < 0)
1629 goto out_unlock;
1630
1631 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001632 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001633 DECLARE_COMPLETION_ONSTACK(compl);
1634
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001635 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001636 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001637 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001638 if (ret < 0)
1639 goto out_sleep;
1640
1641 /* we must unlock here so we will be able to get events */
1642 wl1271_ps_elp_sleep(wl);
1643 mutex_unlock(&wl->mutex);
1644
1645 ret = wait_for_completion_timeout(
1646 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1647 if (ret <= 0) {
1648 wl1271_warning("couldn't enter ps mode!");
1649 ret = -EBUSY;
1650 goto out;
1651 }
1652
1653 /* take mutex again, and wakeup */
1654 mutex_lock(&wl->mutex);
1655
1656 ret = wl1271_ps_elp_wakeup(wl);
1657 if (ret < 0)
1658 goto out_unlock;
1659 }
1660out_sleep:
1661 wl1271_ps_elp_sleep(wl);
1662out_unlock:
1663 mutex_unlock(&wl->mutex);
1664out:
1665 return ret;
1666
1667}
1668
Eliad Peller0603d892011-10-05 11:55:51 +02001669static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1670 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001671{
Eliad Pellere85d1622011-06-27 13:06:43 +03001672 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001673
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001674 mutex_lock(&wl->mutex);
1675
Eliad Peller53d40d02011-10-10 10:13:02 +02001676 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001677 goto out_unlock;
1678
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001679 ret = wl1271_ps_elp_wakeup(wl);
1680 if (ret < 0)
1681 goto out_unlock;
1682
Eliad Peller0603d892011-10-05 11:55:51 +02001683 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001684
1685 wl1271_ps_elp_sleep(wl);
1686out_unlock:
1687 mutex_unlock(&wl->mutex);
1688 return ret;
1689
1690}
1691
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001692static int wl1271_configure_suspend(struct wl1271 *wl,
1693 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001694{
Eliad Peller536129c2011-10-05 11:55:45 +02001695 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001696 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001697 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001698 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001699 return 0;
1700}
1701
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001702static void wl1271_configure_resume(struct wl1271 *wl,
1703 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001704{
1705 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001706 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1707 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001708
1709 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001710 return;
1711
1712 mutex_lock(&wl->mutex);
1713 ret = wl1271_ps_elp_wakeup(wl);
1714 if (ret < 0)
1715 goto out;
1716
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001717 if (is_sta) {
1718 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001719 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001720 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001721 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001722 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001723 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001724 }
Eliad Peller94390642011-05-13 11:57:13 +03001725
1726 wl1271_ps_elp_sleep(wl);
1727out:
1728 mutex_unlock(&wl->mutex);
1729}
1730
Eliad Peller402e48612011-05-13 11:57:09 +03001731static int wl1271_op_suspend(struct ieee80211_hw *hw,
1732 struct cfg80211_wowlan *wow)
1733{
1734 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001735 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001736 int ret;
1737
Eliad Peller402e48612011-05-13 11:57:09 +03001738 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001739 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001740
Eliad Peller4a859df2011-06-06 12:21:52 +03001741 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001742 wl12xx_for_each_wlvif(wl, wlvif) {
1743 ret = wl1271_configure_suspend(wl, wlvif);
1744 if (ret < 0) {
1745 wl1271_warning("couldn't prepare device to suspend");
1746 return ret;
1747 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001748 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001749 /* flush any remaining work */
1750 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001751
1752 /*
1753 * disable and re-enable interrupts in order to flush
1754 * the threaded_irq
1755 */
1756 wl1271_disable_interrupts(wl);
1757
1758 /*
1759 * set suspended flag to avoid triggering a new threaded_irq
1760 * work. no need for spinlock as interrupts are disabled.
1761 */
1762 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1763
1764 wl1271_enable_interrupts(wl);
1765 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001766 wl12xx_for_each_wlvif(wl, wlvif) {
1767 flush_delayed_work(&wlvif->pspoll_work);
1768 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001769 flush_delayed_work(&wl->elp_work);
1770
Eliad Peller402e48612011-05-13 11:57:09 +03001771 return 0;
1772}
1773
1774static int wl1271_op_resume(struct ieee80211_hw *hw)
1775{
1776 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001777 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001778 unsigned long flags;
1779 bool run_irq_work = false;
1780
Eliad Peller402e48612011-05-13 11:57:09 +03001781 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1782 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001783 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001784
1785 /*
1786 * re-enable irq_work enqueuing, and call irq_work directly if
1787 * there is a pending work.
1788 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001789 spin_lock_irqsave(&wl->wl_lock, flags);
1790 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1791 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1792 run_irq_work = true;
1793 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001794
Eliad Peller4a859df2011-06-06 12:21:52 +03001795 if (run_irq_work) {
1796 wl1271_debug(DEBUG_MAC80211,
1797 "run postponed irq_work directly");
1798 wl1271_irq(0, wl);
1799 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001800 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001801 wl12xx_for_each_wlvif(wl, wlvif) {
1802 wl1271_configure_resume(wl, wlvif);
1803 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001804 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001805
Eliad Peller402e48612011-05-13 11:57:09 +03001806 return 0;
1807}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001808#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001809
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001810static int wl1271_op_start(struct ieee80211_hw *hw)
1811{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001812 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1813
1814 /*
1815 * We have to delay the booting of the hardware because
1816 * we need to know the local MAC address before downloading and
1817 * initializing the firmware. The MAC address cannot be changed
1818 * after boot, and without the proper MAC address, the firmware
1819 * will not function properly.
1820 *
1821 * The MAC address is first known when the corresponding interface
1822 * is added. That is where we will initialize the hardware.
1823 */
1824
1825 return 0;
1826}
1827
1828static void wl1271_op_stop(struct ieee80211_hw *hw)
1829{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001830 struct wl1271 *wl = hw->priv;
1831 int i;
1832
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001833 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001834
Eliad Peller10c8cd02011-10-10 10:13:06 +02001835 mutex_lock(&wl->mutex);
1836 if (wl->state == WL1271_STATE_OFF) {
1837 mutex_unlock(&wl->mutex);
1838 return;
1839 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001840 /*
1841 * this must be before the cancel_work calls below, so that the work
1842 * functions don't perform further work.
1843 */
1844 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001845 mutex_unlock(&wl->mutex);
1846
1847 mutex_lock(&wl_list_mutex);
1848 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001849 mutex_unlock(&wl_list_mutex);
1850
1851 wl1271_disable_interrupts(wl);
1852 wl1271_flush_deferred_work(wl);
1853 cancel_delayed_work_sync(&wl->scan_complete_work);
1854 cancel_work_sync(&wl->netstack_work);
1855 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001856 cancel_delayed_work_sync(&wl->elp_work);
1857
1858 /* let's notify MAC80211 about the remaining pending TX frames */
1859 wl12xx_tx_reset(wl, true);
1860 mutex_lock(&wl->mutex);
1861
1862 wl1271_power_off(wl);
1863
1864 wl->band = IEEE80211_BAND_2GHZ;
1865
1866 wl->rx_counter = 0;
1867 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1868 wl->tx_blocks_available = 0;
1869 wl->tx_allocated_blocks = 0;
1870 wl->tx_results_count = 0;
1871 wl->tx_packets_count = 0;
1872 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001873 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1874 wl->ap_fw_ps_map = 0;
1875 wl->ap_ps_map = 0;
1876 wl->sched_scanning = false;
1877 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1878 memset(wl->links_map, 0, sizeof(wl->links_map));
1879 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1880 wl->active_sta_count = 0;
1881
1882 /* The system link is always allocated */
1883 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1884
1885 /*
1886 * this is performed after the cancel_work calls and the associated
1887 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1888 * get executed before all these vars have been reset.
1889 */
1890 wl->flags = 0;
1891
1892 wl->tx_blocks_freed = 0;
1893
1894 for (i = 0; i < NUM_TX_QUEUES; i++) {
1895 wl->tx_pkts_freed[i] = 0;
1896 wl->tx_allocated_pkts[i] = 0;
1897 }
1898
1899 wl1271_debugfs_reset(wl);
1900
1901 kfree(wl->fw_status);
1902 wl->fw_status = NULL;
1903 kfree(wl->tx_res_if);
1904 wl->tx_res_if = NULL;
1905 kfree(wl->target_mem_map);
1906 wl->target_mem_map = NULL;
1907
1908 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001909}
1910
Eliad Pellere5a359f2011-10-10 10:13:15 +02001911static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1912{
1913 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1914 WL12XX_MAX_RATE_POLICIES);
1915 if (policy >= WL12XX_MAX_RATE_POLICIES)
1916 return -EBUSY;
1917
1918 __set_bit(policy, wl->rate_policies_map);
1919 *idx = policy;
1920 return 0;
1921}
1922
1923static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1924{
1925 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1926 return;
1927
1928 __clear_bit(*idx, wl->rate_policies_map);
1929 *idx = WL12XX_MAX_RATE_POLICIES;
1930}
1931
Eliad Peller536129c2011-10-05 11:55:45 +02001932static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001933{
Eliad Peller536129c2011-10-05 11:55:45 +02001934 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001935 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001936 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001937 return WL1271_ROLE_P2P_GO;
1938 else
1939 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001940
1941 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001942 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001943 return WL1271_ROLE_P2P_CL;
1944 else
1945 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001946
Eliad Peller227e81e2011-08-14 13:17:26 +03001947 case BSS_TYPE_IBSS:
1948 return WL1271_ROLE_IBSS;
1949
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001950 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001951 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001952 }
1953 return WL12XX_INVALID_ROLE_TYPE;
1954}
1955
Eliad Peller83587502011-10-10 10:12:53 +02001956static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001957{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001958 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001959 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001960
Eliad Peller48e93e42011-10-10 10:12:58 +02001961 /* clear everything but the persistent data */
1962 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001963
1964 switch (ieee80211_vif_type_p2p(vif)) {
1965 case NL80211_IFTYPE_P2P_CLIENT:
1966 wlvif->p2p = 1;
1967 /* fall-through */
1968 case NL80211_IFTYPE_STATION:
1969 wlvif->bss_type = BSS_TYPE_STA_BSS;
1970 break;
1971 case NL80211_IFTYPE_ADHOC:
1972 wlvif->bss_type = BSS_TYPE_IBSS;
1973 break;
1974 case NL80211_IFTYPE_P2P_GO:
1975 wlvif->p2p = 1;
1976 /* fall-through */
1977 case NL80211_IFTYPE_AP:
1978 wlvif->bss_type = BSS_TYPE_AP_BSS;
1979 break;
1980 default:
1981 wlvif->bss_type = MAX_BSS_TYPE;
1982 return -EOPNOTSUPP;
1983 }
1984
Eliad Peller0603d892011-10-05 11:55:51 +02001985 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001986 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001987 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001988
Eliad Pellere936bbe2011-10-05 11:55:56 +02001989 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1990 wlvif->bss_type == BSS_TYPE_IBSS) {
1991 /* init sta/ibss data */
1992 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001993 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1994 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1995 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001996 } else {
1997 /* init ap data */
1998 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1999 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002000 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2001 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2002 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2003 wl12xx_allocate_rate_policy(wl,
2004 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002005 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002006
Eliad Peller83587502011-10-10 10:12:53 +02002007 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
2008 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002009 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002010 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002011 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02002012 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
2013
Eliad Peller1b92f152011-10-10 10:13:09 +02002014 /*
2015 * mac80211 configures some values globally, while we treat them
2016 * per-interface. thus, on init, we have to copy them from wl
2017 */
2018 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02002019 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02002020 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02002021
Eliad Peller9eb599e2011-10-10 10:12:59 +02002022 INIT_WORK(&wlvif->rx_streaming_enable_work,
2023 wl1271_rx_streaming_enable_work);
2024 INIT_WORK(&wlvif->rx_streaming_disable_work,
2025 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02002026 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02002027 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02002028
Eliad Peller9eb599e2011-10-10 10:12:59 +02002029 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
2030 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002031 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002032}
2033
Eliad Peller1d095472011-10-10 10:12:49 +02002034static bool wl12xx_init_fw(struct wl1271 *wl)
2035{
2036 int retries = WL1271_BOOT_RETRIES;
2037 bool booted = false;
2038 struct wiphy *wiphy = wl->hw->wiphy;
2039 int ret;
2040
2041 while (retries) {
2042 retries--;
2043 ret = wl1271_chip_wakeup(wl);
2044 if (ret < 0)
2045 goto power_off;
2046
2047 ret = wl1271_boot(wl);
2048 if (ret < 0)
2049 goto power_off;
2050
2051 ret = wl1271_hw_init(wl);
2052 if (ret < 0)
2053 goto irq_disable;
2054
2055 booted = true;
2056 break;
2057
2058irq_disable:
2059 mutex_unlock(&wl->mutex);
2060 /* Unlocking the mutex in the middle of handling is
2061 inherently unsafe. In this case we deem it safe to do,
2062 because we need to let any possibly pending IRQ out of
2063 the system (and while we are WL1271_STATE_OFF the IRQ
2064 work function will not do anything.) Also, any other
2065 possible concurrent operations will fail due to the
2066 current state, hence the wl1271 struct should be safe. */
2067 wl1271_disable_interrupts(wl);
2068 wl1271_flush_deferred_work(wl);
2069 cancel_work_sync(&wl->netstack_work);
2070 mutex_lock(&wl->mutex);
2071power_off:
2072 wl1271_power_off(wl);
2073 }
2074
2075 if (!booted) {
2076 wl1271_error("firmware boot failed despite %d retries",
2077 WL1271_BOOT_RETRIES);
2078 goto out;
2079 }
2080
2081 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2082
2083 /* update hw/fw version info in wiphy struct */
2084 wiphy->hw_version = wl->chip.id;
2085 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2086 sizeof(wiphy->fw_version));
2087
2088 /*
2089 * Now we know if 11a is supported (info from the NVS), so disable
2090 * 11a channels if not supported
2091 */
2092 if (!wl->enable_11a)
2093 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2094
2095 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2096 wl->enable_11a ? "" : "not ");
2097
2098 wl->state = WL1271_STATE_ON;
2099out:
2100 return booted;
2101}
2102
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002103static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2104 struct ieee80211_vif *vif)
2105{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002106 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002107 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002108 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002109 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002110 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002111
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002112 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002113 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002114
2115 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002116 ret = wl1271_ps_elp_wakeup(wl);
2117 if (ret < 0)
2118 goto out_unlock;
2119
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002120 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002121 wl1271_debug(DEBUG_MAC80211,
2122 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002123 ret = -EBUSY;
2124 goto out;
2125 }
2126
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002127 /*
2128 * in some very corner case HW recovery scenarios its possible to
2129 * get here before __wl1271_op_remove_interface is complete, so
2130 * opt out if that is the case.
2131 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002132 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2133 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002134 ret = -EBUSY;
2135 goto out;
2136 }
2137
Eliad Peller83587502011-10-10 10:12:53 +02002138 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002139 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002140 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002141
Eliad Peller252efa42011-10-05 11:56:00 +02002142 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002143 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002144 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2145 ret = -EINVAL;
2146 goto out;
2147 }
Eliad Peller1d095472011-10-10 10:12:49 +02002148
Eliad Peller784f6942011-10-05 11:55:39 +02002149 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002150 * TODO: after the nvs issue will be solved, move this block
2151 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002152 */
Eliad Peller1d095472011-10-10 10:12:49 +02002153 if (wl->state == WL1271_STATE_OFF) {
2154 /*
2155 * we still need this in order to configure the fw
2156 * while uploading the nvs
2157 */
2158 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002159
Eliad Peller1d095472011-10-10 10:12:49 +02002160 booted = wl12xx_init_fw(wl);
2161 if (!booted) {
2162 ret = -EINVAL;
2163 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002164 }
Eliad Peller1d095472011-10-10 10:12:49 +02002165 }
Eliad Peller04e80792011-08-14 13:17:09 +03002166
Eliad Peller1d095472011-10-10 10:12:49 +02002167 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2168 wlvif->bss_type == BSS_TYPE_IBSS) {
2169 /*
2170 * The device role is a special role used for
2171 * rx and tx frames prior to association (as
2172 * the STA role can get packets only from
2173 * its associated bssid)
2174 */
Eliad Peller784f6942011-10-05 11:55:39 +02002175 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002176 WL1271_ROLE_DEVICE,
2177 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002178 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002179 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002180 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002181
Eliad Peller1d095472011-10-10 10:12:49 +02002182 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2183 role_type, &wlvif->role_id);
2184 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002185 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002186
2187 ret = wl1271_init_vif_specific(wl, vif);
2188 if (ret < 0)
2189 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002190
2191 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002192 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002193 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002194
2195 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2196 wl->ap_count++;
2197 else
2198 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002199out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002200 wl1271_ps_elp_sleep(wl);
2201out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002202 mutex_unlock(&wl->mutex);
2203
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002204 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002205 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002206 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002207 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002208
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002209 return ret;
2210}
2211
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002212static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002213 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002214 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002215{
Eliad Peller536129c2011-10-05 11:55:45 +02002216 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002217 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002218
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002219 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002220
Eliad Peller10c8cd02011-10-10 10:13:06 +02002221 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2222 return;
2223
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002224 wl->vif = NULL;
2225
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002226 /* because of hardware recovery, we may get here twice */
2227 if (wl->state != WL1271_STATE_ON)
2228 return;
2229
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002230 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002231
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002232 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002233 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002234 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002235
Eliad Pellerbaf62772011-10-10 10:12:52 +02002236 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2237 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002238 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002239 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002240 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002241 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002242 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002243 }
2244
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002245 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2246 /* disable active roles */
2247 ret = wl1271_ps_elp_wakeup(wl);
2248 if (ret < 0)
2249 goto deinit;
2250
Eliad Peller536129c2011-10-05 11:55:45 +02002251 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002252 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002253 if (ret < 0)
2254 goto deinit;
2255 }
2256
Eliad Peller0603d892011-10-05 11:55:51 +02002257 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002258 if (ret < 0)
2259 goto deinit;
2260
2261 wl1271_ps_elp_sleep(wl);
2262 }
2263deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002264 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002265 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002266
2267 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2268 wlvif->bss_type == BSS_TYPE_IBSS) {
2269 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2270 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2271 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2272 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2273 } else {
2274 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2275 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2276 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2277 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2278 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2279 wl12xx_free_rate_policy(wl,
2280 &wlvif->ap.ucast_rate_idx[i]);
2281 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002282
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002283 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002284 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002285 if (wl->last_wlvif == wlvif)
2286 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002287 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002288 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002289 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002290 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002291
Eliad Pellera4e41302011-10-11 11:49:15 +02002292 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2293 wl->ap_count--;
2294 else
2295 wl->sta_count--;
2296
Eliad Pellerbaf62772011-10-10 10:12:52 +02002297 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002298 del_timer_sync(&wlvif->rx_streaming_timer);
2299 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2300 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002301 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002302
Eliad Pellerbaf62772011-10-10 10:12:52 +02002303 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002304}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002305
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002306static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2307 struct ieee80211_vif *vif)
2308{
2309 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002310 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002311 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002312
2313 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002314
2315 if (wl->state == WL1271_STATE_OFF ||
2316 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2317 goto out;
2318
Juuso Oikarinen67353292010-11-18 15:19:02 +02002319 /*
2320 * wl->vif can be null here if someone shuts down the interface
2321 * just when hardware recovery has been started.
2322 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002323 wl12xx_for_each_wlvif(wl, iter) {
2324 if (iter != wlvif)
2325 continue;
2326
Eliad Peller536129c2011-10-05 11:55:45 +02002327 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002328 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002329 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002330 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002331out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002332 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002333 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002334}
2335
Eliad Peller87fbcb02011-10-05 11:55:41 +02002336static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2337 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002338{
2339 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002340 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002341
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002342 /*
2343 * One of the side effects of the JOIN command is that is clears
2344 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2345 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002346 * Currently the only valid scenario for JOIN during association
2347 * is on roaming, in which case we will also be given new keys.
2348 * Keep the below message for now, unless it starts bothering
2349 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002350 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002351 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002352 wl1271_info("JOIN while associated.");
2353
2354 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002355 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002356
Eliad Peller227e81e2011-08-14 13:17:26 +03002357 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002358 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002359 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002360 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002361 if (ret < 0)
2362 goto out;
2363
Eliad Pellerba8447f2011-10-10 10:13:00 +02002364 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002365 goto out;
2366
2367 /*
2368 * The join command disable the keep-alive mode, shut down its process,
2369 * and also clear the template config, so we need to reset it all after
2370 * the join. The acx_aid starts the keep-alive process, and the order
2371 * of the commands below is relevant.
2372 */
Eliad Peller0603d892011-10-05 11:55:51 +02002373 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002374 if (ret < 0)
2375 goto out;
2376
Eliad Peller0603d892011-10-05 11:55:51 +02002377 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002378 if (ret < 0)
2379 goto out;
2380
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002381 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002382 if (ret < 0)
2383 goto out;
2384
Eliad Peller0603d892011-10-05 11:55:51 +02002385 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2386 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002387 ACX_KEEP_ALIVE_TPL_VALID);
2388 if (ret < 0)
2389 goto out;
2390
2391out:
2392 return ret;
2393}
2394
Eliad Peller0603d892011-10-05 11:55:51 +02002395static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002396{
2397 int ret;
2398
Eliad Peller52630c52011-10-10 10:13:08 +02002399 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002400 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2401
Shahar Levi6d158ff2011-09-08 13:01:33 +03002402 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002403 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002404 }
2405
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002406 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002407 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002408 if (ret < 0)
2409 goto out;
2410
Oz Krakowskib992c682011-06-26 10:36:02 +03002411 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002412 wlvif->tx_security_last_seq_lsb = 0;
2413 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002414
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002415out:
2416 return ret;
2417}
2418
Eliad Peller87fbcb02011-10-05 11:55:41 +02002419static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002420{
Eliad Peller1b92f152011-10-10 10:13:09 +02002421 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002422 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002423}
2424
Eliad Peller251c1772011-08-14 13:17:17 +03002425static bool wl12xx_is_roc(struct wl1271 *wl)
2426{
2427 u8 role_id;
2428
2429 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2430 if (role_id >= WL12XX_MAX_ROLES)
2431 return false;
2432
2433 return true;
2434}
2435
Eliad Peller87fbcb02011-10-05 11:55:41 +02002436static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2437 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002438{
2439 int ret;
2440
2441 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002442 /* no need to croc if we weren't busy (e.g. during boot) */
2443 if (wl12xx_is_roc(wl)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002444 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002445 if (ret < 0)
2446 goto out;
2447 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002448 wlvif->rate_set =
2449 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2450 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002451 if (ret < 0)
2452 goto out;
2453 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002454 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002455 ACX_KEEP_ALIVE_TPL_INVALID);
2456 if (ret < 0)
2457 goto out;
2458 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2459 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002460 /* The current firmware only supports sched_scan in idle */
2461 if (wl->sched_scanning) {
2462 wl1271_scan_sched_scan_stop(wl);
2463 ieee80211_sched_scan_stopped(wl->hw);
2464 }
2465
Eliad Peller679a6732011-10-11 11:55:44 +02002466 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002467 if (ret < 0)
2468 goto out;
2469 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2470 }
2471
2472out:
2473 return ret;
2474}
2475
Eliad Peller9f259c42011-10-10 10:13:12 +02002476static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2477 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002478{
Eliad Peller9f259c42011-10-10 10:13:12 +02002479 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2480 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002481
2482 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2483
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002484 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002485 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002486 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002487 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002488 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002489 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002490 wlvif->band = conf->channel->band;
2491 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002492
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002493 if (!is_ap) {
2494 /*
2495 * FIXME: the mac80211 should really provide a fixed
2496 * rate to use here. for now, just use the smallest
2497 * possible rate for the band as a fixed rate for
2498 * association frames and other control messages.
2499 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002500 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002501 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002502
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002503 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002504 wl1271_tx_min_rate_get(wl,
2505 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002506 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002507 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002508 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002509 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002510
Eliad Pellerba8447f2011-10-10 10:13:00 +02002511 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2512 &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002513 if (wl12xx_is_roc(wl)) {
2514 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002515 ret = wl12xx_croc(wl,
2516 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002517 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002518 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002519 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002520 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002521 if (ret < 0)
2522 wl1271_warning("cmd join on channel "
2523 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002524 } else {
2525 /*
2526 * change the ROC channel. do it only if we are
2527 * not idle. otherwise, CROC will be called
2528 * anyway.
2529 */
2530 if (wl12xx_is_roc(wl) &&
2531 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002532 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002533 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002534 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002535
Eliad Peller679a6732011-10-11 11:55:44 +02002536 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002537 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002538 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002539 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002540 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002541 }
2542 }
2543
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002544 /*
2545 * if mac80211 changes the PSM mode, make sure the mode is not
2546 * incorrectly changed after the pspoll failure active window.
2547 */
2548 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002549 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002550
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002551 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002552 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2553 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002554
2555 /*
2556 * We enter PSM only if we're already associated.
2557 * If we're not, we'll enter it when joining an SSID,
2558 * through the bss_info_changed() hook.
2559 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002560 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002561 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002562 ret = wl1271_ps_set_mode(wl, wlvif,
2563 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002564 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002565 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002566 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002567 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002568 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002569
Eliad Pellerc29bb002011-10-10 10:13:03 +02002570 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002571
Eliad Pellerc29bb002011-10-10 10:13:03 +02002572 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002573 ret = wl1271_ps_set_mode(wl, wlvif,
2574 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002575 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002576 }
2577
Eliad Peller6bd65022011-10-10 10:13:11 +02002578 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002579 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002580 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002581 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002582
Eliad Peller6bd65022011-10-10 10:13:11 +02002583 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002584 }
2585
Eliad Peller9f259c42011-10-10 10:13:12 +02002586 return 0;
2587}
2588
2589static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2590{
2591 struct wl1271 *wl = hw->priv;
2592 struct wl12xx_vif *wlvif;
2593 struct ieee80211_conf *conf = &hw->conf;
2594 int channel, ret = 0;
2595
2596 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2597
2598 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2599 " changed 0x%x",
2600 channel,
2601 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2602 conf->power_level,
2603 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2604 changed);
2605
2606 /*
2607 * mac80211 will go to idle nearly immediately after transmitting some
2608 * frames, such as the deauth. To make sure those frames reach the air,
2609 * wait here until the TX queue is fully flushed.
2610 */
2611 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2612 (conf->flags & IEEE80211_CONF_IDLE))
2613 wl1271_tx_flush(wl);
2614
2615 mutex_lock(&wl->mutex);
2616
2617 /* we support configuring the channel and band even while off */
2618 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2619 wl->band = conf->channel->band;
2620 wl->channel = channel;
2621 }
2622
2623 if (changed & IEEE80211_CONF_CHANGE_POWER)
2624 wl->power_level = conf->power_level;
2625
2626 if (unlikely(wl->state == WL1271_STATE_OFF))
2627 goto out;
2628
2629 ret = wl1271_ps_elp_wakeup(wl);
2630 if (ret < 0)
2631 goto out;
2632
2633 /* configure each interface */
2634 wl12xx_for_each_wlvif(wl, wlvif) {
2635 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2636 if (ret < 0)
2637 goto out_sleep;
2638 }
2639
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002640out_sleep:
2641 wl1271_ps_elp_sleep(wl);
2642
2643out:
2644 mutex_unlock(&wl->mutex);
2645
2646 return ret;
2647}
2648
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002649struct wl1271_filter_params {
2650 bool enabled;
2651 int mc_list_length;
2652 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2653};
2654
Jiri Pirko22bedad2010-04-01 21:22:57 +00002655static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2656 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002657{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002658 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002659 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002660 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002661
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002662 if (unlikely(wl->state == WL1271_STATE_OFF))
2663 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002664
Juuso Oikarinen74441132009-10-13 12:47:53 +03002665 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002666 if (!fp) {
2667 wl1271_error("Out of memory setting filters.");
2668 return 0;
2669 }
2670
2671 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002672 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002673 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2674 fp->enabled = false;
2675 } else {
2676 fp->enabled = true;
2677 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002678 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002679 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002680 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002681 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002682 }
2683
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002684 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002685}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002686
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002687#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2688 FIF_ALLMULTI | \
2689 FIF_FCSFAIL | \
2690 FIF_BCN_PRBRESP_PROMISC | \
2691 FIF_CONTROL | \
2692 FIF_OTHER_BSS)
2693
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002694static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2695 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002696 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002697{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002698 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002699 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002700 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002701
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002702 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002703
Arik Nemtsov7d057862010-10-16 19:25:35 +02002704 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2705 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002706
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002707 mutex_lock(&wl->mutex);
2708
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002709 *total &= WL1271_SUPPORTED_FILTERS;
2710 changed &= WL1271_SUPPORTED_FILTERS;
2711
2712 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002713 goto out;
2714
Ido Yariva6208652011-03-01 15:14:41 +02002715 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002716 if (ret < 0)
2717 goto out;
2718
Eliad Peller6e8cd332011-10-10 10:13:13 +02002719 wl12xx_for_each_wlvif(wl, wlvif) {
2720 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2721 if (*total & FIF_ALLMULTI)
2722 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2723 false,
2724 NULL, 0);
2725 else if (fp)
2726 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2727 fp->enabled,
2728 fp->mc_list,
2729 fp->mc_list_length);
2730 if (ret < 0)
2731 goto out_sleep;
2732 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002733 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002734
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002735 /*
2736 * the fw doesn't provide an api to configure the filters. instead,
2737 * the filters configuration is based on the active roles / ROC
2738 * state.
2739 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002740
2741out_sleep:
2742 wl1271_ps_elp_sleep(wl);
2743
2744out:
2745 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002746 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002747}
2748
Eliad Peller170d0e62011-10-05 11:56:06 +02002749static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2750 u8 id, u8 key_type, u8 key_size,
2751 const u8 *key, u8 hlid, u32 tx_seq_32,
2752 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002753{
2754 struct wl1271_ap_key *ap_key;
2755 int i;
2756
2757 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2758
2759 if (key_size > MAX_KEY_SIZE)
2760 return -EINVAL;
2761
2762 /*
2763 * Find next free entry in ap_keys. Also check we are not replacing
2764 * an existing key.
2765 */
2766 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002767 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002768 break;
2769
Eliad Peller170d0e62011-10-05 11:56:06 +02002770 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002771 wl1271_warning("trying to record key replacement");
2772 return -EINVAL;
2773 }
2774 }
2775
2776 if (i == MAX_NUM_KEYS)
2777 return -EBUSY;
2778
2779 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2780 if (!ap_key)
2781 return -ENOMEM;
2782
2783 ap_key->id = id;
2784 ap_key->key_type = key_type;
2785 ap_key->key_size = key_size;
2786 memcpy(ap_key->key, key, key_size);
2787 ap_key->hlid = hlid;
2788 ap_key->tx_seq_32 = tx_seq_32;
2789 ap_key->tx_seq_16 = tx_seq_16;
2790
Eliad Peller170d0e62011-10-05 11:56:06 +02002791 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002792 return 0;
2793}
2794
Eliad Peller170d0e62011-10-05 11:56:06 +02002795static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002796{
2797 int i;
2798
2799 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002800 kfree(wlvif->ap.recorded_keys[i]);
2801 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002802 }
2803}
2804
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002805static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002806{
2807 int i, ret = 0;
2808 struct wl1271_ap_key *key;
2809 bool wep_key_added = false;
2810
2811 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002812 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002813 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002814 break;
2815
Eliad Peller170d0e62011-10-05 11:56:06 +02002816 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002817 hlid = key->hlid;
2818 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002819 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002820
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002821 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002822 key->id, key->key_type,
2823 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002824 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002825 key->tx_seq_16);
2826 if (ret < 0)
2827 goto out;
2828
2829 if (key->key_type == KEY_WEP)
2830 wep_key_added = true;
2831 }
2832
2833 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002834 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002835 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002836 if (ret < 0)
2837 goto out;
2838 }
2839
2840out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002841 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002842 return ret;
2843}
2844
Eliad Peller536129c2011-10-05 11:55:45 +02002845static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2846 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002847 u8 key_size, const u8 *key, u32 tx_seq_32,
2848 u16 tx_seq_16, struct ieee80211_sta *sta)
2849{
2850 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002851 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002852
2853 if (is_ap) {
2854 struct wl1271_station *wl_sta;
2855 u8 hlid;
2856
2857 if (sta) {
2858 wl_sta = (struct wl1271_station *)sta->drv_priv;
2859 hlid = wl_sta->hlid;
2860 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002861 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002862 }
2863
Eliad Peller53d40d02011-10-10 10:13:02 +02002864 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002865 /*
2866 * We do not support removing keys after AP shutdown.
2867 * Pretend we do to make mac80211 happy.
2868 */
2869 if (action != KEY_ADD_OR_REPLACE)
2870 return 0;
2871
Eliad Peller170d0e62011-10-05 11:56:06 +02002872 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002873 key_type, key_size,
2874 key, hlid, tx_seq_32,
2875 tx_seq_16);
2876 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002877 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002878 id, key_type, key_size,
2879 key, hlid, tx_seq_32,
2880 tx_seq_16);
2881 }
2882
2883 if (ret < 0)
2884 return ret;
2885 } else {
2886 const u8 *addr;
2887 static const u8 bcast_addr[ETH_ALEN] = {
2888 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2889 };
2890
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002891 /*
2892 * A STA set to GEM cipher requires 2 tx spare blocks.
2893 * Return to default value when GEM cipher key is removed
2894 */
2895 if (key_type == KEY_GEM) {
2896 if (action == KEY_ADD_OR_REPLACE)
2897 wl->tx_spare_blocks = 2;
2898 else if (action == KEY_REMOVE)
2899 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2900 }
2901
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002902 addr = sta ? sta->addr : bcast_addr;
2903
2904 if (is_zero_ether_addr(addr)) {
2905 /* We dont support TX only encryption */
2906 return -EOPNOTSUPP;
2907 }
2908
2909 /* The wl1271 does not allow to remove unicast keys - they
2910 will be cleared automatically on next CMD_JOIN. Ignore the
2911 request silently, as we dont want the mac80211 to emit
2912 an error message. */
2913 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2914 return 0;
2915
Eliad Peller010d3d32011-08-14 13:17:31 +03002916 /* don't remove key if hlid was already deleted */
2917 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002918 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002919 return 0;
2920
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002921 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002922 id, key_type, key_size,
2923 key, addr, tx_seq_32,
2924 tx_seq_16);
2925 if (ret < 0)
2926 return ret;
2927
2928 /* the default WEP key needs to be configured at least once */
2929 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002930 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002931 wlvif->default_key,
2932 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002933 if (ret < 0)
2934 return ret;
2935 }
2936 }
2937
2938 return 0;
2939}
2940
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002941static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2942 struct ieee80211_vif *vif,
2943 struct ieee80211_sta *sta,
2944 struct ieee80211_key_conf *key_conf)
2945{
2946 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002947 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002948 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002949 u32 tx_seq_32 = 0;
2950 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002951 u8 key_type;
2952
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002953 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2954
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002955 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002956 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002957 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002958 key_conf->keylen, key_conf->flags);
2959 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2960
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002961 mutex_lock(&wl->mutex);
2962
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002963 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2964 ret = -EAGAIN;
2965 goto out_unlock;
2966 }
2967
Ido Yariva6208652011-03-01 15:14:41 +02002968 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002969 if (ret < 0)
2970 goto out_unlock;
2971
Johannes Berg97359d12010-08-10 09:46:38 +02002972 switch (key_conf->cipher) {
2973 case WLAN_CIPHER_SUITE_WEP40:
2974 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002975 key_type = KEY_WEP;
2976
2977 key_conf->hw_key_idx = key_conf->keyidx;
2978 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002979 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002980 key_type = KEY_TKIP;
2981
2982 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002983 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2984 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002985 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002986 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002987 key_type = KEY_AES;
2988
2989 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Eliad Peller48e93e42011-10-10 10:12:58 +02002990 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2991 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002992 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002993 case WL1271_CIPHER_SUITE_GEM:
2994 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002995 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2996 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002997 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002998 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002999 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003000
3001 ret = -EOPNOTSUPP;
3002 goto out_sleep;
3003 }
3004
3005 switch (cmd) {
3006 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003007 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003008 key_conf->keyidx, key_type,
3009 key_conf->keylen, key_conf->key,
3010 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003011 if (ret < 0) {
3012 wl1271_error("Could not add or replace key");
3013 goto out_sleep;
3014 }
3015 break;
3016
3017 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003018 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003019 key_conf->keyidx, key_type,
3020 key_conf->keylen, key_conf->key,
3021 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003022 if (ret < 0) {
3023 wl1271_error("Could not remove key");
3024 goto out_sleep;
3025 }
3026 break;
3027
3028 default:
3029 wl1271_error("Unsupported key cmd 0x%x", cmd);
3030 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003031 break;
3032 }
3033
3034out_sleep:
3035 wl1271_ps_elp_sleep(wl);
3036
3037out_unlock:
3038 mutex_unlock(&wl->mutex);
3039
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003040 return ret;
3041}
3042
3043static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003044 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003045 struct cfg80211_scan_request *req)
3046{
3047 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003048 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3049
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003050 int ret;
3051 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003052 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003053
3054 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3055
3056 if (req->n_ssids) {
3057 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003058 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003059 }
3060
3061 mutex_lock(&wl->mutex);
3062
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003063 if (wl->state == WL1271_STATE_OFF) {
3064 /*
3065 * We cannot return -EBUSY here because cfg80211 will expect
3066 * a call to ieee80211_scan_completed if we do - in this case
3067 * there won't be any call.
3068 */
3069 ret = -EAGAIN;
3070 goto out;
3071 }
3072
Ido Yariva6208652011-03-01 15:14:41 +02003073 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003074 if (ret < 0)
3075 goto out;
3076
Eliad Peller251c1772011-08-14 13:17:17 +03003077 /* cancel ROC before scanning */
3078 if (wl12xx_is_roc(wl)) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02003079 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03003080 /* don't allow scanning right now */
3081 ret = -EBUSY;
3082 goto out_sleep;
3083 }
Eliad Peller679a6732011-10-11 11:55:44 +02003084 wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003085 }
3086
Eliad Peller784f6942011-10-05 11:55:39 +02003087 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003088out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003089 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003090out:
3091 mutex_unlock(&wl->mutex);
3092
3093 return ret;
3094}
3095
Eliad Peller73ecce32011-06-27 13:06:45 +03003096static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3097 struct ieee80211_vif *vif)
3098{
3099 struct wl1271 *wl = hw->priv;
3100 int ret;
3101
3102 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3103
3104 mutex_lock(&wl->mutex);
3105
3106 if (wl->state == WL1271_STATE_OFF)
3107 goto out;
3108
3109 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3110 goto out;
3111
3112 ret = wl1271_ps_elp_wakeup(wl);
3113 if (ret < 0)
3114 goto out;
3115
3116 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3117 ret = wl1271_scan_stop(wl);
3118 if (ret < 0)
3119 goto out_sleep;
3120 }
3121 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3122 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003123 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003124 wl->scan.req = NULL;
3125 ieee80211_scan_completed(wl->hw, true);
3126
3127out_sleep:
3128 wl1271_ps_elp_sleep(wl);
3129out:
3130 mutex_unlock(&wl->mutex);
3131
3132 cancel_delayed_work_sync(&wl->scan_complete_work);
3133}
3134
Luciano Coelho33c2c062011-05-10 14:46:02 +03003135static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3136 struct ieee80211_vif *vif,
3137 struct cfg80211_sched_scan_request *req,
3138 struct ieee80211_sched_scan_ies *ies)
3139{
3140 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003141 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003142 int ret;
3143
3144 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3145
3146 mutex_lock(&wl->mutex);
3147
3148 ret = wl1271_ps_elp_wakeup(wl);
3149 if (ret < 0)
3150 goto out;
3151
Eliad Peller536129c2011-10-05 11:55:45 +02003152 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003153 if (ret < 0)
3154 goto out_sleep;
3155
Eliad Peller536129c2011-10-05 11:55:45 +02003156 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003157 if (ret < 0)
3158 goto out_sleep;
3159
3160 wl->sched_scanning = true;
3161
3162out_sleep:
3163 wl1271_ps_elp_sleep(wl);
3164out:
3165 mutex_unlock(&wl->mutex);
3166 return ret;
3167}
3168
3169static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3170 struct ieee80211_vif *vif)
3171{
3172 struct wl1271 *wl = hw->priv;
3173 int ret;
3174
3175 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3176
3177 mutex_lock(&wl->mutex);
3178
3179 ret = wl1271_ps_elp_wakeup(wl);
3180 if (ret < 0)
3181 goto out;
3182
3183 wl1271_scan_sched_scan_stop(wl);
3184
3185 wl1271_ps_elp_sleep(wl);
3186out:
3187 mutex_unlock(&wl->mutex);
3188}
3189
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003190static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3191{
3192 struct wl1271 *wl = hw->priv;
3193 int ret = 0;
3194
3195 mutex_lock(&wl->mutex);
3196
3197 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3198 ret = -EAGAIN;
3199 goto out;
3200 }
3201
Ido Yariva6208652011-03-01 15:14:41 +02003202 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003203 if (ret < 0)
3204 goto out;
3205
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003206 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003207 if (ret < 0)
3208 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3209
3210 wl1271_ps_elp_sleep(wl);
3211
3212out:
3213 mutex_unlock(&wl->mutex);
3214
3215 return ret;
3216}
3217
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003218static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3219{
3220 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003221 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003222 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003223
3224 mutex_lock(&wl->mutex);
3225
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003226 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3227 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003228 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003229 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003230
Ido Yariva6208652011-03-01 15:14:41 +02003231 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003232 if (ret < 0)
3233 goto out;
3234
Eliad Peller6e8cd332011-10-10 10:13:13 +02003235 wl12xx_for_each_wlvif(wl, wlvif) {
3236 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3237 if (ret < 0)
3238 wl1271_warning("set rts threshold failed: %d", ret);
3239 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003240 wl1271_ps_elp_sleep(wl);
3241
3242out:
3243 mutex_unlock(&wl->mutex);
3244
3245 return ret;
3246}
3247
Eliad Peller1fe9f162011-10-05 11:55:48 +02003248static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003249 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003250{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003251 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003252 u8 ssid_len;
3253 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3254 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003255
Eliad Peller889cb362011-05-01 09:56:45 +03003256 if (!ptr) {
3257 wl1271_error("No SSID in IEs!");
3258 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003259 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003260
Eliad Peller889cb362011-05-01 09:56:45 +03003261 ssid_len = ptr[1];
3262 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3263 wl1271_error("SSID is too long!");
3264 return -EINVAL;
3265 }
3266
Eliad Peller1fe9f162011-10-05 11:55:48 +02003267 wlvif->ssid_len = ssid_len;
3268 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003269 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003270}
3271
Eliad Pellerd48055d2011-09-15 12:07:04 +03003272static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3273{
3274 int len;
3275 const u8 *next, *end = skb->data + skb->len;
3276 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3277 skb->len - ieoffset);
3278 if (!ie)
3279 return;
3280 len = ie[1] + 2;
3281 next = ie + len;
3282 memmove(ie, next, end - next);
3283 skb_trim(skb, skb->len - len);
3284}
3285
Eliad Peller26b4bf22011-09-15 12:07:05 +03003286static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3287 unsigned int oui, u8 oui_type,
3288 int ieoffset)
3289{
3290 int len;
3291 const u8 *next, *end = skb->data + skb->len;
3292 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3293 skb->data + ieoffset,
3294 skb->len - ieoffset);
3295 if (!ie)
3296 return;
3297 len = ie[1] + 2;
3298 next = ie + len;
3299 memmove(ie, next, end - next);
3300 skb_trim(skb, skb->len - len);
3301}
3302
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003303static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3304 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003305{
3306 struct sk_buff *skb;
3307 int ret;
3308
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003309 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003310 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003311 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003312
3313 ret = wl1271_cmd_template_set(wl,
3314 CMD_TEMPL_AP_PROBE_RESPONSE,
3315 skb->data,
3316 skb->len, 0,
3317 rates);
3318
3319 dev_kfree_skb(skb);
3320 return ret;
3321}
3322
3323static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3324 struct ieee80211_vif *vif,
3325 u8 *probe_rsp_data,
3326 size_t probe_rsp_len,
3327 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003328{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003329 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3330 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003331 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3332 int ssid_ie_offset, ie_offset, templ_len;
3333 const u8 *ptr;
3334
3335 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003336 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003337 return wl1271_cmd_template_set(wl,
3338 CMD_TEMPL_AP_PROBE_RESPONSE,
3339 probe_rsp_data,
3340 probe_rsp_len, 0,
3341 rates);
3342
3343 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3344 wl1271_error("probe_rsp template too big");
3345 return -EINVAL;
3346 }
3347
3348 /* start searching from IE offset */
3349 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3350
3351 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3352 probe_rsp_len - ie_offset);
3353 if (!ptr) {
3354 wl1271_error("No SSID in beacon!");
3355 return -EINVAL;
3356 }
3357
3358 ssid_ie_offset = ptr - probe_rsp_data;
3359 ptr += (ptr[1] + 2);
3360
3361 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3362
3363 /* insert SSID from bss_conf */
3364 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3365 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3366 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3367 bss_conf->ssid, bss_conf->ssid_len);
3368 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3369
3370 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3371 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3372 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3373
3374 return wl1271_cmd_template_set(wl,
3375 CMD_TEMPL_AP_PROBE_RESPONSE,
3376 probe_rsp_templ,
3377 templ_len, 0,
3378 rates);
3379}
3380
Arik Nemtsove78a2872010-10-16 19:07:21 +02003381static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003382 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003383 struct ieee80211_bss_conf *bss_conf,
3384 u32 changed)
3385{
Eliad Peller0603d892011-10-05 11:55:51 +02003386 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003387 int ret = 0;
3388
3389 if (changed & BSS_CHANGED_ERP_SLOT) {
3390 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003391 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003392 else
Eliad Peller0603d892011-10-05 11:55:51 +02003393 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003394 if (ret < 0) {
3395 wl1271_warning("Set slot time failed %d", ret);
3396 goto out;
3397 }
3398 }
3399
3400 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3401 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003402 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003403 else
Eliad Peller0603d892011-10-05 11:55:51 +02003404 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003405 }
3406
3407 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3408 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003409 ret = wl1271_acx_cts_protect(wl, wlvif,
3410 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003411 else
Eliad Peller0603d892011-10-05 11:55:51 +02003412 ret = wl1271_acx_cts_protect(wl, wlvif,
3413 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003414 if (ret < 0) {
3415 wl1271_warning("Set ctsprotect failed %d", ret);
3416 goto out;
3417 }
3418 }
3419
3420out:
3421 return ret;
3422}
3423
3424static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3425 struct ieee80211_vif *vif,
3426 struct ieee80211_bss_conf *bss_conf,
3427 u32 changed)
3428{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003429 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003430 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003431 int ret = 0;
3432
3433 if ((changed & BSS_CHANGED_BEACON_INT)) {
3434 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3435 bss_conf->beacon_int);
3436
Eliad Peller6a899792011-10-05 11:55:58 +02003437 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003438 }
3439
Arik Nemtsov560f0022011-11-08 18:46:54 +02003440 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3441 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003442 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3443 wl1271_debug(DEBUG_AP, "probe response updated");
3444 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3445 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003446 }
3447
Arik Nemtsove78a2872010-10-16 19:07:21 +02003448 if ((changed & BSS_CHANGED_BEACON)) {
3449 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003450 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003451 int ieoffset = offsetof(struct ieee80211_mgmt,
3452 u.beacon.variable);
3453 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3454 u16 tmpl_id;
3455
Arik Nemtsov560f0022011-11-08 18:46:54 +02003456 if (!beacon) {
3457 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003458 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003459 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003460
3461 wl1271_debug(DEBUG_MASTER, "beacon updated");
3462
Eliad Peller1fe9f162011-10-05 11:55:48 +02003463 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003464 if (ret < 0) {
3465 dev_kfree_skb(beacon);
3466 goto out;
3467 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003468 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003469 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3470 CMD_TEMPL_BEACON;
3471 ret = wl1271_cmd_template_set(wl, tmpl_id,
3472 beacon->data,
3473 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003474 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003475 if (ret < 0) {
3476 dev_kfree_skb(beacon);
3477 goto out;
3478 }
3479
Arik Nemtsov560f0022011-11-08 18:46:54 +02003480 /*
3481 * In case we already have a probe-resp beacon set explicitly
3482 * by usermode, don't use the beacon data.
3483 */
3484 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3485 goto end_bcn;
3486
Eliad Pellerd48055d2011-09-15 12:07:04 +03003487 /* remove TIM ie from probe response */
3488 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3489
Eliad Peller26b4bf22011-09-15 12:07:05 +03003490 /*
3491 * remove p2p ie from probe response.
3492 * the fw reponds to probe requests that don't include
3493 * the p2p ie. probe requests with p2p ie will be passed,
3494 * and will be responded by the supplicant (the spec
3495 * forbids including the p2p ie when responding to probe
3496 * requests that didn't include it).
3497 */
3498 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3499 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3500
Arik Nemtsove78a2872010-10-16 19:07:21 +02003501 hdr = (struct ieee80211_hdr *) beacon->data;
3502 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3503 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003504 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003505 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003506 beacon->data,
3507 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003508 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003509 else
3510 ret = wl1271_cmd_template_set(wl,
3511 CMD_TEMPL_PROBE_RESPONSE,
3512 beacon->data,
3513 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003514 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003515end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003516 dev_kfree_skb(beacon);
3517 if (ret < 0)
3518 goto out;
3519 }
3520
3521out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003522 if (ret != 0)
3523 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003524 return ret;
3525}
3526
3527/* AP mode changes */
3528static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003529 struct ieee80211_vif *vif,
3530 struct ieee80211_bss_conf *bss_conf,
3531 u32 changed)
3532{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003533 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003534 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003535
Arik Nemtsove78a2872010-10-16 19:07:21 +02003536 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3537 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003538
Eliad Peller87fbcb02011-10-05 11:55:41 +02003539 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003540 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003541 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003542 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003543
Eliad Peller87fbcb02011-10-05 11:55:41 +02003544 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003545 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003546 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003547 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003548 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003549
Eliad Peller784f6942011-10-05 11:55:39 +02003550 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003551 if (ret < 0)
3552 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003553 }
3554
Arik Nemtsove78a2872010-10-16 19:07:21 +02003555 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3556 if (ret < 0)
3557 goto out;
3558
3559 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3560 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003561 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003562 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003563 if (ret < 0)
3564 goto out;
3565
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003566 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003567 if (ret < 0)
3568 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003569
Eliad Peller53d40d02011-10-10 10:13:02 +02003570 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003571 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003572 }
3573 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003574 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003575 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003576 if (ret < 0)
3577 goto out;
3578
Eliad Peller53d40d02011-10-10 10:13:02 +02003579 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003580 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3581 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003582 wl1271_debug(DEBUG_AP, "stopped AP");
3583 }
3584 }
3585 }
3586
Eliad Peller0603d892011-10-05 11:55:51 +02003587 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003588 if (ret < 0)
3589 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003590
3591 /* Handle HT information change */
3592 if ((changed & BSS_CHANGED_HT) &&
3593 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003594 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003595 bss_conf->ht_operation_mode);
3596 if (ret < 0) {
3597 wl1271_warning("Set ht information failed %d", ret);
3598 goto out;
3599 }
3600 }
3601
Arik Nemtsove78a2872010-10-16 19:07:21 +02003602out:
3603 return;
3604}
3605
3606/* STA/IBSS mode changes */
3607static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3608 struct ieee80211_vif *vif,
3609 struct ieee80211_bss_conf *bss_conf,
3610 u32 changed)
3611{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003612 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003613 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003614 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003615 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003616 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003617 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003618 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003619 bool sta_exists = false;
3620 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003621
3622 if (is_ibss) {
3623 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3624 changed);
3625 if (ret < 0)
3626 goto out;
3627 }
3628
Eliad Peller227e81e2011-08-14 13:17:26 +03003629 if (changed & BSS_CHANGED_IBSS) {
3630 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003631 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003632 ibss_joined = true;
3633 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003634 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3635 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003636 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003637 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003638 }
3639 }
3640 }
3641
3642 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003643 do_join = true;
3644
3645 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003646 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003647 do_join = true;
3648
Eliad Peller227e81e2011-08-14 13:17:26 +03003649 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003650 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3651 bss_conf->enable_beacon ? "enabled" : "disabled");
3652
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003653 do_join = true;
3654 }
3655
Eliad Pellerc31e4942011-10-23 08:21:55 +02003656 if (changed & BSS_CHANGED_IDLE) {
3657 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3658 if (ret < 0)
3659 wl1271_warning("idle mode change failed %d", ret);
3660 }
3661
Arik Nemtsove78a2872010-10-16 19:07:21 +02003662 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003663 bool enable = false;
3664 if (bss_conf->cqm_rssi_thold)
3665 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003666 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003667 bss_conf->cqm_rssi_thold,
3668 bss_conf->cqm_rssi_hyst);
3669 if (ret < 0)
3670 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003671 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003672 }
3673
Eliad Pellercdf09492011-10-05 11:55:44 +02003674 if (changed & BSS_CHANGED_BSSID)
3675 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003676 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003677 if (ret < 0)
3678 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003679
Eliad Peller784f6942011-10-05 11:55:39 +02003680 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003681 if (ret < 0)
3682 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003683
Eliad Pellerfa287b82010-12-26 09:27:50 +01003684 /* Need to update the BSSID (for filtering etc) */
3685 do_join = true;
3686 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003687
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003688 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3689 rcu_read_lock();
3690 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3691 if (!sta)
3692 goto sta_not_found;
3693
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003694 /* save the supp_rates of the ap */
3695 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3696 if (sta->ht_cap.ht_supported)
3697 sta_rate_set |=
3698 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003699 sta_ht_cap = sta->ht_cap;
3700 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003701
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003702sta_not_found:
3703 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003704 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003705
Arik Nemtsove78a2872010-10-16 19:07:21 +02003706 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003707 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003708 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003709 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003710 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003711 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003712
Eliad Peller74ec8392011-10-05 11:56:02 +02003713 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003714
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003715 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003716 * use basic rates from AP, and determine lowest rate
3717 * to use with control frames.
3718 */
3719 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003720 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003721 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003722 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003723 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003724 wl1271_tx_min_rate_get(wl,
3725 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003726 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003727 wlvif->rate_set =
3728 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003729 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003730 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003731 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003732 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003733 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003734
3735 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003736 * with wl1271, we don't need to update the
3737 * beacon_int and dtim_period, because the firmware
3738 * updates it by itself when the first beacon is
3739 * received after a join.
3740 */
Eliad Peller6840e372011-10-05 11:55:50 +02003741 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003742 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003743 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003744
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003745 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003746 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003747 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003748 dev_kfree_skb(wlvif->probereq);
3749 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003750 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003751 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003752 ieoffset = offsetof(struct ieee80211_mgmt,
3753 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003754 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003755
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003756 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003757 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003758 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003759 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003760 } else {
3761 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003762 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003763 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3764 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003765 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003766 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3767 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003768 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003769
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003770 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003771 dev_kfree_skb(wlvif->probereq);
3772 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003773
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003774 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003775 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003776
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003777 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003778 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003779 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003780 wl1271_tx_min_rate_get(wl,
3781 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003782 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003783 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003784 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003785
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003786 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003787 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003788
3789 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003790 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003791 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003792 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003793
3794 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003795 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003796 u32 conf_flags = wl->hw->conf.flags;
3797 /*
3798 * we might have to disable roc, if there was
3799 * no IF_OPER_UP notification.
3800 */
3801 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003802 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003803 if (ret < 0)
3804 goto out;
3805 }
3806 /*
3807 * (we also need to disable roc in case of
3808 * roaming on the same channel. until we will
3809 * have a better flow...)
3810 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003811 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3812 ret = wl12xx_croc(wl,
3813 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003814 if (ret < 0)
3815 goto out;
3816 }
3817
Eliad Peller0603d892011-10-05 11:55:51 +02003818 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003819 if (!(conf_flags & IEEE80211_CONF_IDLE))
3820 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003821 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003822 }
3823 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003824
Eliad Pellerd192d262011-05-24 14:33:08 +03003825 if (changed & BSS_CHANGED_IBSS) {
3826 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3827 bss_conf->ibss_joined);
3828
3829 if (bss_conf->ibss_joined) {
3830 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003831 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003832 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003833 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003834 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003835 wl1271_tx_min_rate_get(wl,
3836 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003837
Shahar Levi06b660e2011-09-05 13:54:36 +03003838 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003839 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3840 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003841 if (ret < 0)
3842 goto out;
3843 }
3844 }
3845
Eliad Peller0603d892011-10-05 11:55:51 +02003846 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003847 if (ret < 0)
3848 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003849
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003850 if (changed & BSS_CHANGED_ARP_FILTER) {
3851 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003852 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003853
Eliad Pellerc5312772010-12-09 11:31:27 +02003854 if (bss_conf->arp_addr_cnt == 1 &&
3855 bss_conf->arp_filter_enabled) {
3856 /*
3857 * The template should have been configured only upon
3858 * association. however, it seems that the correct ip
3859 * isn't being set (when sending), so we have to
3860 * reconfigure the template upon every ip change.
3861 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003862 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003863 if (ret < 0) {
3864 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003865 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003866 }
3867
Eliad Peller0603d892011-10-05 11:55:51 +02003868 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003869 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003870 addr);
3871 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003872 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003873
3874 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003875 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003876 }
3877
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003878 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003879 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003880 if (ret < 0) {
3881 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003882 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003883 }
Eliad Peller251c1772011-08-14 13:17:17 +03003884
3885 /* ROC until connected (after EAPOL exchange) */
3886 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003887 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003888 if (ret < 0)
3889 goto out;
3890
Eliad Pellerba8447f2011-10-10 10:13:00 +02003891 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003892 ieee80211_get_operstate(vif));
3893 }
3894 /*
3895 * stop device role if started (we might already be in
3896 * STA role). TODO: make it better.
3897 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003898 if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) {
Eliad Peller679a6732011-10-11 11:55:44 +02003899 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003900 if (ret < 0)
3901 goto out;
3902 }
Eliad Peller05dba352011-08-23 16:37:01 +03003903
3904 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003905 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3906 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003907 enum wl1271_cmd_ps_mode mode;
3908
3909 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003910 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003911 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003912 true);
3913 if (ret < 0)
3914 goto out;
3915 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003916 }
3917
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003918 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003919 if (sta_exists) {
3920 if ((changed & BSS_CHANGED_HT) &&
3921 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003922 ret = wl1271_acx_set_ht_capabilities(wl,
3923 &sta_ht_cap,
3924 true,
Eliad Peller154da672011-10-05 11:55:53 +02003925 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003926 if (ret < 0) {
3927 wl1271_warning("Set ht cap true failed %d",
3928 ret);
3929 goto out;
3930 }
3931 }
3932 /* handle new association without HT and disassociation */
3933 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003934 ret = wl1271_acx_set_ht_capabilities(wl,
3935 &sta_ht_cap,
3936 false,
Eliad Peller154da672011-10-05 11:55:53 +02003937 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003938 if (ret < 0) {
3939 wl1271_warning("Set ht cap false failed %d",
3940 ret);
3941 goto out;
3942 }
3943 }
3944 }
3945
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003946 /* Handle HT information change. Done after join. */
3947 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003948 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003949 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003950 bss_conf->ht_operation_mode);
3951 if (ret < 0) {
3952 wl1271_warning("Set ht information failed %d", ret);
3953 goto out;
3954 }
3955 }
3956
Arik Nemtsove78a2872010-10-16 19:07:21 +02003957out:
3958 return;
3959}
3960
3961static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3962 struct ieee80211_vif *vif,
3963 struct ieee80211_bss_conf *bss_conf,
3964 u32 changed)
3965{
3966 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003967 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3968 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003969 int ret;
3970
3971 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3972 (int)changed);
3973
3974 mutex_lock(&wl->mutex);
3975
3976 if (unlikely(wl->state == WL1271_STATE_OFF))
3977 goto out;
3978
Eliad Peller10c8cd02011-10-10 10:13:06 +02003979 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3980 goto out;
3981
Ido Yariva6208652011-03-01 15:14:41 +02003982 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003983 if (ret < 0)
3984 goto out;
3985
3986 if (is_ap)
3987 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3988 else
3989 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3990
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003991 wl1271_ps_elp_sleep(wl);
3992
3993out:
3994 mutex_unlock(&wl->mutex);
3995}
3996
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003997static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3998 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003999 const struct ieee80211_tx_queue_params *params)
4000{
4001 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02004002 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02004003 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004004 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02004005
4006 mutex_lock(&wl->mutex);
4007
4008 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
4009
Kalle Valo4695dc92010-03-18 12:26:38 +02004010 if (params->uapsd)
4011 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
4012 else
4013 ps_scheme = CONF_PS_SCHEME_LEGACY;
4014
Arik Nemtsov488fc542010-10-16 20:33:45 +02004015 if (wl->state == WL1271_STATE_OFF) {
4016 /*
4017 * If the state is off, the parameters will be recorded and
4018 * configured on init. This happens in AP-mode.
4019 */
4020 struct conf_tx_ac_category *conf_ac =
4021 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
4022 struct conf_tx_tid *conf_tid =
4023 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
4024
4025 conf_ac->ac = wl1271_tx_get_queue(queue);
4026 conf_ac->cw_min = (u8)params->cw_min;
4027 conf_ac->cw_max = params->cw_max;
4028 conf_ac->aifsn = params->aifs;
4029 conf_ac->tx_op_limit = params->txop << 5;
4030
4031 conf_tid->queue_id = wl1271_tx_get_queue(queue);
4032 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
4033 conf_tid->tsid = wl1271_tx_get_queue(queue);
4034 conf_tid->ps_scheme = ps_scheme;
4035 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
4036 conf_tid->apsd_conf[0] = 0;
4037 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004038 goto out;
4039 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02004040
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004041 ret = wl1271_ps_elp_wakeup(wl);
4042 if (ret < 0)
4043 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004044
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004045 /*
4046 * the txop is confed in units of 32us by the mac80211,
4047 * we need us
4048 */
Eliad Peller0603d892011-10-05 11:55:51 +02004049 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004050 params->cw_min, params->cw_max,
4051 params->aifs, params->txop << 5);
4052 if (ret < 0)
4053 goto out_sleep;
4054
Eliad Peller0603d892011-10-05 11:55:51 +02004055 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004056 CONF_CHANNEL_TYPE_EDCF,
4057 wl1271_tx_get_queue(queue),
4058 ps_scheme, CONF_ACK_POLICY_LEGACY,
4059 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004060
4061out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004062 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004063
4064out:
4065 mutex_unlock(&wl->mutex);
4066
4067 return ret;
4068}
4069
Eliad Peller37a41b42011-09-21 14:06:11 +03004070static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4071 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004072{
4073
4074 struct wl1271 *wl = hw->priv;
4075 u64 mactime = ULLONG_MAX;
4076 int ret;
4077
4078 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4079
4080 mutex_lock(&wl->mutex);
4081
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004082 if (unlikely(wl->state == WL1271_STATE_OFF))
4083 goto out;
4084
Ido Yariva6208652011-03-01 15:14:41 +02004085 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004086 if (ret < 0)
4087 goto out;
4088
4089 ret = wl1271_acx_tsf_info(wl, &mactime);
4090 if (ret < 0)
4091 goto out_sleep;
4092
4093out_sleep:
4094 wl1271_ps_elp_sleep(wl);
4095
4096out:
4097 mutex_unlock(&wl->mutex);
4098 return mactime;
4099}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004100
John W. Linvilleece550d2010-07-28 16:41:06 -04004101static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4102 struct survey_info *survey)
4103{
4104 struct wl1271 *wl = hw->priv;
4105 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004106
John W. Linvilleece550d2010-07-28 16:41:06 -04004107 if (idx != 0)
4108 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004109
John W. Linvilleece550d2010-07-28 16:41:06 -04004110 survey->channel = conf->channel;
4111 survey->filled = SURVEY_INFO_NOISE_DBM;
4112 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004113
John W. Linvilleece550d2010-07-28 16:41:06 -04004114 return 0;
4115}
4116
Arik Nemtsov409622e2011-02-23 00:22:29 +02004117static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004118 struct wl12xx_vif *wlvif,
4119 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004120{
4121 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004122 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004123
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004124
4125 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004126 wl1271_warning("could not allocate HLID - too much stations");
4127 return -EBUSY;
4128 }
4129
4130 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004131 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4132 if (ret < 0) {
4133 wl1271_warning("could not allocate HLID - too many links");
4134 return -EBUSY;
4135 }
4136
4137 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004138 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004139 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004140 return 0;
4141}
4142
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004143void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004144{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004145 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004146 return;
4147
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004148 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004149 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004150 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004151 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004152 __clear_bit(hlid, &wl->ap_ps_map);
4153 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004154 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004155 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004156}
4157
4158static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4159 struct ieee80211_vif *vif,
4160 struct ieee80211_sta *sta)
4161{
4162 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004163 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004164 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004165 int ret = 0;
4166 u8 hlid;
4167
4168 mutex_lock(&wl->mutex);
4169
4170 if (unlikely(wl->state == WL1271_STATE_OFF))
4171 goto out;
4172
Eliad Peller536129c2011-10-05 11:55:45 +02004173 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004174 goto out;
4175
4176 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4177
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004178 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004179 if (ret < 0)
4180 goto out;
4181
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004182 wl_sta = (struct wl1271_station *)sta->drv_priv;
4183 hlid = wl_sta->hlid;
4184
Ido Yariva6208652011-03-01 15:14:41 +02004185 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004186 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004187 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004188
Eliad Peller1b92f152011-10-10 10:13:09 +02004189 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004190 if (ret < 0)
4191 goto out_sleep;
4192
Eliad Pellerb67476e2011-08-14 13:17:23 +03004193 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4194 if (ret < 0)
4195 goto out_sleep;
4196
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004197 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4198 if (ret < 0)
4199 goto out_sleep;
4200
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004201out_sleep:
4202 wl1271_ps_elp_sleep(wl);
4203
Arik Nemtsov409622e2011-02-23 00:22:29 +02004204out_free_sta:
4205 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004206 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004207
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004208out:
4209 mutex_unlock(&wl->mutex);
4210 return ret;
4211}
4212
4213static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4214 struct ieee80211_vif *vif,
4215 struct ieee80211_sta *sta)
4216{
4217 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004218 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004219 struct wl1271_station *wl_sta;
4220 int ret = 0, id;
4221
4222 mutex_lock(&wl->mutex);
4223
4224 if (unlikely(wl->state == WL1271_STATE_OFF))
4225 goto out;
4226
Eliad Peller536129c2011-10-05 11:55:45 +02004227 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004228 goto out;
4229
4230 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4231
4232 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004233 id = wl_sta->hlid;
4234 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004235 goto out;
4236
Ido Yariva6208652011-03-01 15:14:41 +02004237 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004238 if (ret < 0)
4239 goto out;
4240
Eliad Pellerc690ec82011-08-14 13:17:07 +03004241 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004242 if (ret < 0)
4243 goto out_sleep;
4244
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004245 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004246
4247out_sleep:
4248 wl1271_ps_elp_sleep(wl);
4249
4250out:
4251 mutex_unlock(&wl->mutex);
4252 return ret;
4253}
4254
Luciano Coelho4623ec72011-03-21 19:26:41 +02004255static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4256 struct ieee80211_vif *vif,
4257 enum ieee80211_ampdu_mlme_action action,
4258 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4259 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004260{
4261 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004262 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004263 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004264 u8 hlid, *ba_bitmap;
4265
4266 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4267 tid);
4268
4269 /* sanity check - the fields in FW are only 8bits wide */
4270 if (WARN_ON(tid > 0xFF))
4271 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004272
4273 mutex_lock(&wl->mutex);
4274
4275 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4276 ret = -EAGAIN;
4277 goto out;
4278 }
4279
Eliad Peller536129c2011-10-05 11:55:45 +02004280 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004281 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004282 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004283 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004284 struct wl1271_station *wl_sta;
4285
4286 wl_sta = (struct wl1271_station *)sta->drv_priv;
4287 hlid = wl_sta->hlid;
4288 ba_bitmap = &wl->links[hlid].ba_bitmap;
4289 } else {
4290 ret = -EINVAL;
4291 goto out;
4292 }
4293
Ido Yariva6208652011-03-01 15:14:41 +02004294 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004295 if (ret < 0)
4296 goto out;
4297
Shahar Levi70559a02011-05-22 16:10:22 +03004298 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4299 tid, action);
4300
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004301 switch (action) {
4302 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004303 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004304 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004305 break;
4306 }
4307
4308 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4309 ret = -EBUSY;
4310 wl1271_error("exceeded max RX BA sessions");
4311 break;
4312 }
4313
4314 if (*ba_bitmap & BIT(tid)) {
4315 ret = -EINVAL;
4316 wl1271_error("cannot enable RX BA session on active "
4317 "tid: %d", tid);
4318 break;
4319 }
4320
4321 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4322 hlid);
4323 if (!ret) {
4324 *ba_bitmap |= BIT(tid);
4325 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004326 }
4327 break;
4328
4329 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004330 if (!(*ba_bitmap & BIT(tid))) {
4331 ret = -EINVAL;
4332 wl1271_error("no active RX BA session on tid: %d",
4333 tid);
4334 break;
4335 }
4336
4337 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4338 hlid);
4339 if (!ret) {
4340 *ba_bitmap &= ~BIT(tid);
4341 wl->ba_rx_session_count--;
4342 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004343 break;
4344
4345 /*
4346 * The BA initiator session management in FW independently.
4347 * Falling break here on purpose for all TX APDU commands.
4348 */
4349 case IEEE80211_AMPDU_TX_START:
4350 case IEEE80211_AMPDU_TX_STOP:
4351 case IEEE80211_AMPDU_TX_OPERATIONAL:
4352 ret = -EINVAL;
4353 break;
4354
4355 default:
4356 wl1271_error("Incorrect ampdu action id=%x\n", action);
4357 ret = -EINVAL;
4358 }
4359
4360 wl1271_ps_elp_sleep(wl);
4361
4362out:
4363 mutex_unlock(&wl->mutex);
4364
4365 return ret;
4366}
4367
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004368static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4369 struct ieee80211_vif *vif,
4370 const struct cfg80211_bitrate_mask *mask)
4371{
Eliad Peller83587502011-10-10 10:12:53 +02004372 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004373 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004374 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004375
4376 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4377 mask->control[NL80211_BAND_2GHZ].legacy,
4378 mask->control[NL80211_BAND_5GHZ].legacy);
4379
4380 mutex_lock(&wl->mutex);
4381
4382 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004383 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004384 wl1271_tx_enabled_rates_get(wl,
4385 mask->control[i].legacy,
4386 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004387
4388 if (unlikely(wl->state == WL1271_STATE_OFF))
4389 goto out;
4390
4391 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4392 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4393
4394 ret = wl1271_ps_elp_wakeup(wl);
4395 if (ret < 0)
4396 goto out;
4397
4398 wl1271_set_band_rate(wl, wlvif);
4399 wlvif->basic_rate =
4400 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4401 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4402
4403 wl1271_ps_elp_sleep(wl);
4404 }
4405out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004406 mutex_unlock(&wl->mutex);
4407
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004408 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004409}
4410
Shahar Levi6d158ff2011-09-08 13:01:33 +03004411static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4412 struct ieee80211_channel_switch *ch_switch)
4413{
4414 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004415 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004416 int ret;
4417
4418 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4419
4420 mutex_lock(&wl->mutex);
4421
4422 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004423 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4424 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4425 ieee80211_chswitch_done(vif, false);
4426 }
4427 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004428 }
4429
4430 ret = wl1271_ps_elp_wakeup(wl);
4431 if (ret < 0)
4432 goto out;
4433
Eliad Peller52630c52011-10-10 10:13:08 +02004434 /* TODO: change mac80211 to pass vif as param */
4435 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4436 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004437
Eliad Peller52630c52011-10-10 10:13:08 +02004438 if (!ret)
4439 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4440 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004441
4442 wl1271_ps_elp_sleep(wl);
4443
4444out:
4445 mutex_unlock(&wl->mutex);
4446}
4447
Arik Nemtsov33437892011-04-26 23:35:39 +03004448static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4449{
4450 struct wl1271 *wl = hw->priv;
4451 bool ret = false;
4452
4453 mutex_lock(&wl->mutex);
4454
4455 if (unlikely(wl->state == WL1271_STATE_OFF))
4456 goto out;
4457
4458 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004459 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004460out:
4461 mutex_unlock(&wl->mutex);
4462
4463 return ret;
4464}
4465
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004466/* can't be const, mac80211 writes to this */
4467static struct ieee80211_rate wl1271_rates[] = {
4468 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004469 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4470 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004471 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004472 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4473 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004474 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4475 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004476 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4477 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004478 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4479 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004480 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4481 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004482 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4483 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004484 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4485 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004486 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004487 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4488 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004489 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004490 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4491 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004492 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004493 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4494 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004495 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004496 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4497 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004498 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004499 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4500 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004501 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004502 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4503 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004504 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004505 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4506 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004507};
4508
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004509/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004510static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004511 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004512 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004513 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4514 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4515 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004516 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004517 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4518 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4519 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004520 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004521 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4522 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4523 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004524 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004525};
4526
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004527/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004528static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004529 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004530 7, /* CONF_HW_RXTX_RATE_MCS7 */
4531 6, /* CONF_HW_RXTX_RATE_MCS6 */
4532 5, /* CONF_HW_RXTX_RATE_MCS5 */
4533 4, /* CONF_HW_RXTX_RATE_MCS4 */
4534 3, /* CONF_HW_RXTX_RATE_MCS3 */
4535 2, /* CONF_HW_RXTX_RATE_MCS2 */
4536 1, /* CONF_HW_RXTX_RATE_MCS1 */
4537 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004538
4539 11, /* CONF_HW_RXTX_RATE_54 */
4540 10, /* CONF_HW_RXTX_RATE_48 */
4541 9, /* CONF_HW_RXTX_RATE_36 */
4542 8, /* CONF_HW_RXTX_RATE_24 */
4543
4544 /* TI-specific rate */
4545 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4546
4547 7, /* CONF_HW_RXTX_RATE_18 */
4548 6, /* CONF_HW_RXTX_RATE_12 */
4549 3, /* CONF_HW_RXTX_RATE_11 */
4550 5, /* CONF_HW_RXTX_RATE_9 */
4551 4, /* CONF_HW_RXTX_RATE_6 */
4552 2, /* CONF_HW_RXTX_RATE_5_5 */
4553 1, /* CONF_HW_RXTX_RATE_2 */
4554 0 /* CONF_HW_RXTX_RATE_1 */
4555};
4556
Shahar Levie8b03a22010-10-13 16:09:39 +02004557/* 11n STA capabilities */
4558#define HW_RX_HIGHEST_RATE 72
4559
Shahar Levi00d20102010-11-08 11:20:10 +00004560#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004561 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4562 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004563 .ht_supported = true, \
4564 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4565 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4566 .mcs = { \
4567 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4568 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4569 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4570 }, \
4571}
4572
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004573/* can't be const, mac80211 writes to this */
4574static struct ieee80211_supported_band wl1271_band_2ghz = {
4575 .channels = wl1271_channels,
4576 .n_channels = ARRAY_SIZE(wl1271_channels),
4577 .bitrates = wl1271_rates,
4578 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004579 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004580};
4581
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004582/* 5 GHz data rates for WL1273 */
4583static struct ieee80211_rate wl1271_rates_5ghz[] = {
4584 { .bitrate = 60,
4585 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4586 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4587 { .bitrate = 90,
4588 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4589 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4590 { .bitrate = 120,
4591 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4592 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4593 { .bitrate = 180,
4594 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4595 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4596 { .bitrate = 240,
4597 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4598 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4599 { .bitrate = 360,
4600 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4601 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4602 { .bitrate = 480,
4603 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4604 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4605 { .bitrate = 540,
4606 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4607 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4608};
4609
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004610/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004611static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004612 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4613 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4614 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4615 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4616 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4617 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4618 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4619 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4620 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4621 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4622 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4623 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4624 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4625 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4626 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4627 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4628 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4629 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4630 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4631 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4632 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4633 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4634 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4635 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4636 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4637 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4638 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4639 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4640 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4641 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4642 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4643 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4644 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4645 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004646};
4647
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004648/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004649static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004650 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004651 7, /* CONF_HW_RXTX_RATE_MCS7 */
4652 6, /* CONF_HW_RXTX_RATE_MCS6 */
4653 5, /* CONF_HW_RXTX_RATE_MCS5 */
4654 4, /* CONF_HW_RXTX_RATE_MCS4 */
4655 3, /* CONF_HW_RXTX_RATE_MCS3 */
4656 2, /* CONF_HW_RXTX_RATE_MCS2 */
4657 1, /* CONF_HW_RXTX_RATE_MCS1 */
4658 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004659
4660 7, /* CONF_HW_RXTX_RATE_54 */
4661 6, /* CONF_HW_RXTX_RATE_48 */
4662 5, /* CONF_HW_RXTX_RATE_36 */
4663 4, /* CONF_HW_RXTX_RATE_24 */
4664
4665 /* TI-specific rate */
4666 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4667
4668 3, /* CONF_HW_RXTX_RATE_18 */
4669 2, /* CONF_HW_RXTX_RATE_12 */
4670 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4671 1, /* CONF_HW_RXTX_RATE_9 */
4672 0, /* CONF_HW_RXTX_RATE_6 */
4673 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4674 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4675 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4676};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004677
4678static struct ieee80211_supported_band wl1271_band_5ghz = {
4679 .channels = wl1271_channels_5ghz,
4680 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4681 .bitrates = wl1271_rates_5ghz,
4682 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004683 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004684};
4685
Tobias Klausera0ea9492010-05-20 10:38:11 +02004686static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004687 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4688 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4689};
4690
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004691static const struct ieee80211_ops wl1271_ops = {
4692 .start = wl1271_op_start,
4693 .stop = wl1271_op_stop,
4694 .add_interface = wl1271_op_add_interface,
4695 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004696#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004697 .suspend = wl1271_op_suspend,
4698 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004699#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004700 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004701 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004702 .configure_filter = wl1271_op_configure_filter,
4703 .tx = wl1271_op_tx,
4704 .set_key = wl1271_op_set_key,
4705 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004706 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004707 .sched_scan_start = wl1271_op_sched_scan_start,
4708 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004709 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004710 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004711 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004712 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004713 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004714 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004715 .sta_add = wl1271_op_sta_add,
4716 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004717 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004718 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004719 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004720 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004721 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004722};
4723
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004724
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004725u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004726{
4727 u8 idx;
4728
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004729 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004730
4731 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4732 wl1271_error("Illegal RX rate from HW: %d", rate);
4733 return 0;
4734 }
4735
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004736 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004737 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4738 wl1271_error("Unsupported RX rate from HW: %d", rate);
4739 return 0;
4740 }
4741
4742 return idx;
4743}
4744
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004745static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4746 struct device_attribute *attr,
4747 char *buf)
4748{
4749 struct wl1271 *wl = dev_get_drvdata(dev);
4750 ssize_t len;
4751
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004752 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004753
4754 mutex_lock(&wl->mutex);
4755 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4756 wl->sg_enabled);
4757 mutex_unlock(&wl->mutex);
4758
4759 return len;
4760
4761}
4762
4763static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4764 struct device_attribute *attr,
4765 const char *buf, size_t count)
4766{
4767 struct wl1271 *wl = dev_get_drvdata(dev);
4768 unsigned long res;
4769 int ret;
4770
Luciano Coelho6277ed62011-04-01 17:49:54 +03004771 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004772 if (ret < 0) {
4773 wl1271_warning("incorrect value written to bt_coex_mode");
4774 return count;
4775 }
4776
4777 mutex_lock(&wl->mutex);
4778
4779 res = !!res;
4780
4781 if (res == wl->sg_enabled)
4782 goto out;
4783
4784 wl->sg_enabled = res;
4785
4786 if (wl->state == WL1271_STATE_OFF)
4787 goto out;
4788
Ido Yariva6208652011-03-01 15:14:41 +02004789 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004790 if (ret < 0)
4791 goto out;
4792
4793 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4794 wl1271_ps_elp_sleep(wl);
4795
4796 out:
4797 mutex_unlock(&wl->mutex);
4798 return count;
4799}
4800
4801static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4802 wl1271_sysfs_show_bt_coex_state,
4803 wl1271_sysfs_store_bt_coex_state);
4804
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004805static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4806 struct device_attribute *attr,
4807 char *buf)
4808{
4809 struct wl1271 *wl = dev_get_drvdata(dev);
4810 ssize_t len;
4811
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004812 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004813
4814 mutex_lock(&wl->mutex);
4815 if (wl->hw_pg_ver >= 0)
4816 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4817 else
4818 len = snprintf(buf, len, "n/a\n");
4819 mutex_unlock(&wl->mutex);
4820
4821 return len;
4822}
4823
Gery Kahn6f07b722011-07-18 14:21:49 +03004824static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004825 wl1271_sysfs_show_hw_pg_ver, NULL);
4826
Ido Yariv95dac04f2011-06-06 14:57:06 +03004827static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4828 struct bin_attribute *bin_attr,
4829 char *buffer, loff_t pos, size_t count)
4830{
4831 struct device *dev = container_of(kobj, struct device, kobj);
4832 struct wl1271 *wl = dev_get_drvdata(dev);
4833 ssize_t len;
4834 int ret;
4835
4836 ret = mutex_lock_interruptible(&wl->mutex);
4837 if (ret < 0)
4838 return -ERESTARTSYS;
4839
4840 /* Let only one thread read the log at a time, blocking others */
4841 while (wl->fwlog_size == 0) {
4842 DEFINE_WAIT(wait);
4843
4844 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4845 &wait,
4846 TASK_INTERRUPTIBLE);
4847
4848 if (wl->fwlog_size != 0) {
4849 finish_wait(&wl->fwlog_waitq, &wait);
4850 break;
4851 }
4852
4853 mutex_unlock(&wl->mutex);
4854
4855 schedule();
4856 finish_wait(&wl->fwlog_waitq, &wait);
4857
4858 if (signal_pending(current))
4859 return -ERESTARTSYS;
4860
4861 ret = mutex_lock_interruptible(&wl->mutex);
4862 if (ret < 0)
4863 return -ERESTARTSYS;
4864 }
4865
4866 /* Check if the fwlog is still valid */
4867 if (wl->fwlog_size < 0) {
4868 mutex_unlock(&wl->mutex);
4869 return 0;
4870 }
4871
4872 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4873 len = min(count, (size_t)wl->fwlog_size);
4874 wl->fwlog_size -= len;
4875 memcpy(buffer, wl->fwlog, len);
4876
4877 /* Make room for new messages */
4878 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4879
4880 mutex_unlock(&wl->mutex);
4881
4882 return len;
4883}
4884
4885static struct bin_attribute fwlog_attr = {
4886 .attr = {.name = "fwlog", .mode = S_IRUSR},
4887 .read = wl1271_sysfs_read_fwlog,
4888};
4889
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004890static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004891{
4892 int ret;
4893
4894 if (wl->mac80211_registered)
4895 return 0;
4896
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004897 ret = wl1271_fetch_nvs(wl);
4898 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004899 /* NOTE: The wl->nvs->nvs element must be first, in
4900 * order to simplify the casting, we assume it is at
4901 * the beginning of the wl->nvs structure.
4902 */
4903 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004904
4905 wl->mac_addr[0] = nvs_ptr[11];
4906 wl->mac_addr[1] = nvs_ptr[10];
4907 wl->mac_addr[2] = nvs_ptr[6];
4908 wl->mac_addr[3] = nvs_ptr[5];
4909 wl->mac_addr[4] = nvs_ptr[4];
4910 wl->mac_addr[5] = nvs_ptr[3];
4911 }
4912
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004913 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4914
4915 ret = ieee80211_register_hw(wl->hw);
4916 if (ret < 0) {
4917 wl1271_error("unable to register mac80211 hw: %d", ret);
4918 return ret;
4919 }
4920
4921 wl->mac80211_registered = true;
4922
Eliad Pellerd60080a2010-11-24 12:53:16 +02004923 wl1271_debugfs_init(wl);
4924
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004925 register_netdevice_notifier(&wl1271_dev_notifier);
4926
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004927 wl1271_notice("loaded");
4928
4929 return 0;
4930}
4931
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004932static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004933{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004934 if (wl->state == WL1271_STATE_PLT)
4935 __wl1271_plt_stop(wl);
4936
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004937 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004938 ieee80211_unregister_hw(wl->hw);
4939 wl->mac80211_registered = false;
4940
4941}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004942
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004943static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004944{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004945 static const u32 cipher_suites[] = {
4946 WLAN_CIPHER_SUITE_WEP40,
4947 WLAN_CIPHER_SUITE_WEP104,
4948 WLAN_CIPHER_SUITE_TKIP,
4949 WLAN_CIPHER_SUITE_CCMP,
4950 WL1271_CIPHER_SUITE_GEM,
4951 };
4952
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004953 /* The tx descriptor buffer and the TKIP space. */
4954 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4955 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004956
4957 /* unit us */
4958 /* FIXME: find a proper value */
4959 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004960 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004961
4962 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004963 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004964 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004965 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004966 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004967 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004968 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004969 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004970 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004971 IEEE80211_HW_AP_LINK_PS |
4972 IEEE80211_HW_AMPDU_AGGREGATION |
4973 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004974
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004975 wl->hw->wiphy->cipher_suites = cipher_suites;
4976 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4977
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004978 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004979 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4980 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004981 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004982 wl->hw->wiphy->max_sched_scan_ssids = 16;
4983 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004984 /*
4985 * Maximum length of elements in scanning probe request templates
4986 * should be the maximum length possible for a template, without
4987 * the IEEE80211 header of the template
4988 */
Eliad Peller154037d2011-08-14 13:17:12 +03004989 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004990 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004991
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004992 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4993 sizeof(struct ieee80211_header);
4994
Eliad Peller1ec23f72011-08-25 14:26:54 +03004995 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4996
Luciano Coelho4a31c112011-03-21 23:16:14 +02004997 /* make sure all our channels fit in the scanned_ch bitmask */
4998 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4999 ARRAY_SIZE(wl1271_channels_5ghz) >
5000 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005001 /*
5002 * We keep local copies of the band structs because we need to
5003 * modify them on a per-device basis.
5004 */
5005 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
5006 sizeof(wl1271_band_2ghz));
5007 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
5008 sizeof(wl1271_band_5ghz));
5009
5010 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
5011 &wl->bands[IEEE80211_BAND_2GHZ];
5012 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
5013 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005014
Kalle Valo12bd8942010-03-18 12:26:33 +02005015 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02005016 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02005017
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01005018 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
5019
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02005020 /* the FW answers probe-requests in AP-mode */
5021 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
5022 wl->hw->wiphy->probe_resp_offload =
5023 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
5024 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
5025 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
5026
Felipe Balbia390e852011-10-06 10:07:44 +03005027 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005028
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005029 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02005030 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005031
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005032 wl->hw->max_rx_aggregation_subframes = 8;
5033
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005034 return 0;
5035}
5036
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005037#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005038
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005039static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005040{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005041 struct ieee80211_hw *hw;
5042 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005043 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005044 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005045
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005046 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005047
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005048 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5049 if (!hw) {
5050 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005051 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005052 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005053 }
5054
5055 wl = hw->priv;
5056 memset(wl, 0, sizeof(*wl));
5057
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005058 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005059 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005060
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005061 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005062
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005063 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005064 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005065 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5066
Ido Yariva6208652011-03-01 15:14:41 +02005067 skb_queue_head_init(&wl->deferred_rx_queue);
5068 skb_queue_head_init(&wl->deferred_tx_queue);
5069
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005070 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005071 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005072 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5073 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5074 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005075
Eliad Peller92ef8962011-06-07 12:50:46 +03005076 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5077 if (!wl->freezable_wq) {
5078 ret = -ENOMEM;
5079 goto err_hw;
5080 }
5081
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005082 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005083 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005084 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005085 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005086 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005087 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005088 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005089 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005090 wl->ap_ps_map = 0;
5091 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005092 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005093 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005094 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005095 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005096 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005097 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005098 wl->fwlog_size = 0;
5099 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005100
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005101 /* The system link is always allocated */
5102 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5103
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005104 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005105 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005106 wl->tx_frames[i] = NULL;
5107
5108 spin_lock_init(&wl->wl_lock);
5109
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005110 wl->state = WL1271_STATE_OFF;
5111 mutex_init(&wl->mutex);
5112
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005113 /* Apply default driver configuration. */
5114 wl1271_conf_init(wl);
5115
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005116 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5117 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5118 if (!wl->aggr_buf) {
5119 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005120 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005121 }
5122
Ido Yariv990f5de2011-03-31 10:06:59 +02005123 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5124 if (!wl->dummy_packet) {
5125 ret = -ENOMEM;
5126 goto err_aggr;
5127 }
5128
Ido Yariv95dac04f2011-06-06 14:57:06 +03005129 /* Allocate one page for the FW log */
5130 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5131 if (!wl->fwlog) {
5132 ret = -ENOMEM;
5133 goto err_dummy_packet;
5134 }
5135
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005136 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005137
Ido Yariv990f5de2011-03-31 10:06:59 +02005138err_dummy_packet:
5139 dev_kfree_skb(wl->dummy_packet);
5140
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005141err_aggr:
5142 free_pages((unsigned long)wl->aggr_buf, order);
5143
Eliad Peller92ef8962011-06-07 12:50:46 +03005144err_wq:
5145 destroy_workqueue(wl->freezable_wq);
5146
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005147err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005148 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005149 ieee80211_free_hw(hw);
5150
5151err_hw_alloc:
5152
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005153 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005154}
5155
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005156static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005157{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005158 /* Unblock any fwlog readers */
5159 mutex_lock(&wl->mutex);
5160 wl->fwlog_size = -1;
5161 wake_up_interruptible_all(&wl->fwlog_waitq);
5162 mutex_unlock(&wl->mutex);
5163
Felipe Balbif79f8902011-10-06 13:05:25 +03005164 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005165
Felipe Balbif79f8902011-10-06 13:05:25 +03005166 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005167
Felipe Balbif79f8902011-10-06 13:05:25 +03005168 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005169 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005170 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005171 free_pages((unsigned long)wl->aggr_buf,
5172 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005173
5174 wl1271_debugfs_exit(wl);
5175
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005176 vfree(wl->fw);
5177 wl->fw = NULL;
5178 kfree(wl->nvs);
5179 wl->nvs = NULL;
5180
5181 kfree(wl->fw_status);
5182 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005183 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005184
5185 ieee80211_free_hw(wl->hw);
5186
5187 return 0;
5188}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005189
Felipe Balbia390e852011-10-06 10:07:44 +03005190static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5191{
5192 struct wl1271 *wl = cookie;
5193 unsigned long flags;
5194
5195 wl1271_debug(DEBUG_IRQ, "IRQ");
5196
5197 /* complete the ELP completion */
5198 spin_lock_irqsave(&wl->wl_lock, flags);
5199 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5200 if (wl->elp_compl) {
5201 complete(wl->elp_compl);
5202 wl->elp_compl = NULL;
5203 }
5204
5205 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5206 /* don't enqueue a work right now. mark it as pending */
5207 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5208 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5209 disable_irq_nosync(wl->irq);
5210 pm_wakeup_event(wl->dev, 0);
5211 spin_unlock_irqrestore(&wl->wl_lock, flags);
5212 return IRQ_HANDLED;
5213 }
5214 spin_unlock_irqrestore(&wl->wl_lock, flags);
5215
5216 return IRQ_WAKE_THREAD;
5217}
5218
Felipe Balbice2a2172011-10-05 14:12:55 +03005219static int __devinit wl12xx_probe(struct platform_device *pdev)
5220{
Felipe Balbia390e852011-10-06 10:07:44 +03005221 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5222 struct ieee80211_hw *hw;
5223 struct wl1271 *wl;
5224 unsigned long irqflags;
5225 int ret = -ENODEV;
5226
5227 hw = wl1271_alloc_hw();
5228 if (IS_ERR(hw)) {
5229 wl1271_error("can't allocate hw");
5230 ret = PTR_ERR(hw);
5231 goto out;
5232 }
5233
5234 wl = hw->priv;
5235 wl->irq = platform_get_irq(pdev, 0);
5236 wl->ref_clock = pdata->board_ref_clock;
5237 wl->tcxo_clock = pdata->board_tcxo_clock;
5238 wl->platform_quirks = pdata->platform_quirks;
5239 wl->set_power = pdata->set_power;
5240 wl->dev = &pdev->dev;
5241 wl->if_ops = pdata->ops;
5242
5243 platform_set_drvdata(pdev, wl);
5244
5245 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5246 irqflags = IRQF_TRIGGER_RISING;
5247 else
5248 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5249
5250 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5251 irqflags,
5252 pdev->name, wl);
5253 if (ret < 0) {
5254 wl1271_error("request_irq() failed: %d", ret);
5255 goto out_free_hw;
5256 }
5257
5258 ret = enable_irq_wake(wl->irq);
5259 if (!ret) {
5260 wl->irq_wake_enabled = true;
5261 device_init_wakeup(wl->dev, 1);
5262 if (pdata->pwr_in_suspend)
5263 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5264
5265 }
5266 disable_irq(wl->irq);
5267
5268 ret = wl1271_init_ieee80211(wl);
5269 if (ret)
5270 goto out_irq;
5271
5272 ret = wl1271_register_hw(wl);
5273 if (ret)
5274 goto out_irq;
5275
Felipe Balbif79f8902011-10-06 13:05:25 +03005276 /* Create sysfs file to control bt coex state */
5277 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5278 if (ret < 0) {
5279 wl1271_error("failed to create sysfs file bt_coex_state");
5280 goto out_irq;
5281 }
5282
5283 /* Create sysfs file to get HW PG version */
5284 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5285 if (ret < 0) {
5286 wl1271_error("failed to create sysfs file hw_pg_ver");
5287 goto out_bt_coex_state;
5288 }
5289
5290 /* Create sysfs file for the FW log */
5291 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5292 if (ret < 0) {
5293 wl1271_error("failed to create sysfs file fwlog");
5294 goto out_hw_pg_ver;
5295 }
5296
Felipe Balbice2a2172011-10-05 14:12:55 +03005297 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005298
Felipe Balbif79f8902011-10-06 13:05:25 +03005299out_hw_pg_ver:
5300 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5301
5302out_bt_coex_state:
5303 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5304
Felipe Balbia390e852011-10-06 10:07:44 +03005305out_irq:
5306 free_irq(wl->irq, wl);
5307
5308out_free_hw:
5309 wl1271_free_hw(wl);
5310
5311out:
5312 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005313}
5314
5315static int __devexit wl12xx_remove(struct platform_device *pdev)
5316{
Felipe Balbia390e852011-10-06 10:07:44 +03005317 struct wl1271 *wl = platform_get_drvdata(pdev);
5318
5319 if (wl->irq_wake_enabled) {
5320 device_init_wakeup(wl->dev, 0);
5321 disable_irq_wake(wl->irq);
5322 }
5323 wl1271_unregister_hw(wl);
5324 free_irq(wl->irq, wl);
5325 wl1271_free_hw(wl);
5326
Felipe Balbice2a2172011-10-05 14:12:55 +03005327 return 0;
5328}
5329
5330static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005331 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005332 { } /* Terminating Entry */
5333};
5334MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5335
5336static struct platform_driver wl12xx_driver = {
5337 .probe = wl12xx_probe,
5338 .remove = __devexit_p(wl12xx_remove),
5339 .id_table = wl12xx_id_table,
5340 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005341 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005342 .owner = THIS_MODULE,
5343 }
5344};
5345
5346static int __init wl12xx_init(void)
5347{
5348 return platform_driver_register(&wl12xx_driver);
5349}
5350module_init(wl12xx_init);
5351
5352static void __exit wl12xx_exit(void)
5353{
5354 platform_driver_unregister(&wl12xx_driver);
5355}
5356module_exit(wl12xx_exit);
5357
Guy Eilam491bbd62011-01-12 10:33:29 +01005358u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005359EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005360module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005361MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5362
Ido Yariv95dac04f2011-06-06 14:57:06 +03005363module_param_named(fwlog, fwlog_param, charp, 0);
5364MODULE_PARM_DESC(keymap,
5365 "FW logger options: continuous, ondemand, dbgpins or disable");
5366
Eliad Peller2a5bff02011-08-25 18:10:59 +03005367module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5368MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5369
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005370MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005371MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005372MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");