blob: 51d519f93d79fe9604ce5810aa837a0805daee62 [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) {
1058 wl1271_error("could not get firmware: %d", ret);
1059 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) {
1096 wl1271_error("could not get nvs file: %d", ret);
1097 return ret;
1098 }
1099
Shahar Levibc765bf2011-03-06 16:32:10 +02001100 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001101
1102 if (!wl->nvs) {
1103 wl1271_error("could not allocate memory for the nvs file");
1104 ret = -ENOMEM;
1105 goto out;
1106 }
1107
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001108 wl->nvs_len = fw->size;
1109
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001110out:
1111 release_firmware(fw);
1112
1113 return ret;
1114}
1115
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001116void wl12xx_queue_recovery_work(struct wl1271 *wl)
1117{
1118 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1119 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1120}
1121
Ido Yariv95dac04f2011-06-06 14:57:06 +03001122size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1123{
1124 size_t len = 0;
1125
1126 /* The FW log is a length-value list, find where the log end */
1127 while (len < maxlen) {
1128 if (memblock[len] == 0)
1129 break;
1130 if (len + memblock[len] + 1 > maxlen)
1131 break;
1132 len += memblock[len] + 1;
1133 }
1134
1135 /* Make sure we have enough room */
1136 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1137
1138 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1139 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1140 wl->fwlog_size += len;
1141
1142 return len;
1143}
1144
1145static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1146{
1147 u32 addr;
1148 u32 first_addr;
1149 u8 *block;
1150
1151 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1152 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1153 (wl->conf.fwlog.mem_blocks == 0))
1154 return;
1155
1156 wl1271_info("Reading FW panic log");
1157
1158 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1159 if (!block)
1160 return;
1161
1162 /*
1163 * Make sure the chip is awake and the logger isn't active.
1164 * This might fail if the firmware hanged.
1165 */
1166 if (!wl1271_ps_elp_wakeup(wl))
1167 wl12xx_cmd_stop_fwlog(wl);
1168
1169 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001170 wl12xx_fw_status(wl, wl->fw_status);
1171 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001172 if (!first_addr)
1173 goto out;
1174
1175 /* Traverse the memory blocks linked list */
1176 addr = first_addr;
1177 do {
1178 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1179 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1180 false);
1181
1182 /*
1183 * Memory blocks are linked to one another. The first 4 bytes
1184 * of each memory block hold the hardware address of the next
1185 * one. The last memory block points to the first one.
1186 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001187 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001188 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1189 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1190 break;
1191 } while (addr && (addr != first_addr));
1192
1193 wake_up_interruptible(&wl->fwlog_waitq);
1194
1195out:
1196 kfree(block);
1197}
1198
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001199static void wl1271_recovery_work(struct work_struct *work)
1200{
1201 struct wl1271 *wl =
1202 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001203 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001204 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001205
1206 mutex_lock(&wl->mutex);
1207
1208 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001209 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001210
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001211 /* Avoid a recursive recovery */
1212 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1213
Ido Yariv95dac04f2011-06-06 14:57:06 +03001214 wl12xx_read_fwlog_panic(wl);
1215
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001216 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1217 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001218
Eliad Peller2a5bff02011-08-25 18:10:59 +03001219 BUG_ON(bug_on_recovery);
1220
Oz Krakowskib992c682011-06-26 10:36:02 +03001221 /*
1222 * Advance security sequence number to overcome potential progress
1223 * in the firmware during recovery. This doens't hurt if the network is
1224 * not encrypted.
1225 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001226 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001227 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001228 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001229 wlvif->tx_security_seq +=
1230 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1231 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001232
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001233 /* Prevent spurious TX during FW restart */
1234 ieee80211_stop_queues(wl->hw);
1235
Luciano Coelho33c2c062011-05-10 14:46:02 +03001236 if (wl->sched_scanning) {
1237 ieee80211_sched_scan_stopped(wl->hw);
1238 wl->sched_scanning = false;
1239 }
1240
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001241 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001242 while (!list_empty(&wl->wlvif_list)) {
1243 wlvif = list_first_entry(&wl->wlvif_list,
1244 struct wl12xx_vif, list);
1245 vif = wl12xx_wlvif_to_vif(wlvif);
1246 __wl1271_op_remove_interface(wl, vif, false);
1247 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001248 mutex_unlock(&wl->mutex);
1249 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001250
1251 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1252
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001253 ieee80211_restart_hw(wl->hw);
1254
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001255 /*
1256 * Its safe to enable TX now - the queues are stopped after a request
1257 * to restart the HW.
1258 */
1259 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001260 return;
1261out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001262 mutex_unlock(&wl->mutex);
1263}
1264
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001265static void wl1271_fw_wakeup(struct wl1271 *wl)
1266{
1267 u32 elp_reg;
1268
1269 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001270 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001271}
1272
1273static int wl1271_setup(struct wl1271 *wl)
1274{
1275 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1276 if (!wl->fw_status)
1277 return -ENOMEM;
1278
1279 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1280 if (!wl->tx_res_if) {
1281 kfree(wl->fw_status);
1282 return -ENOMEM;
1283 }
1284
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 return 0;
1286}
1287
1288static int wl1271_chip_wakeup(struct wl1271 *wl)
1289{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001290 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291 int ret = 0;
1292
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001293 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001294 ret = wl1271_power_on(wl);
1295 if (ret < 0)
1296 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001297 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001298 wl1271_io_reset(wl);
1299 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001300
1301 /* We don't need a real memory partition here, because we only want
1302 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001303 memset(&partition, 0, sizeof(partition));
1304 partition.reg.start = REGISTERS_BASE;
1305 partition.reg.size = REGISTERS_DOWN_SIZE;
1306 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001307
1308 /* ELP module wake up */
1309 wl1271_fw_wakeup(wl);
1310
1311 /* whal_FwCtrl_BootSm() */
1312
1313 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001314 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315
1316 /* 1. check if chip id is valid */
1317
1318 switch (wl->chip.id) {
1319 case CHIP_ID_1271_PG10:
1320 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1321 wl->chip.id);
1322
1323 ret = wl1271_setup(wl);
1324 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001325 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001326 break;
1327 case CHIP_ID_1271_PG20:
1328 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1329 wl->chip.id);
1330
1331 ret = wl1271_setup(wl);
1332 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001333 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001334 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001335 case CHIP_ID_1283_PG20:
1336 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1337 wl->chip.id);
1338
1339 ret = wl1271_setup(wl);
1340 if (ret < 0)
1341 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001342
Ido Yariv0da13da2011-03-31 10:06:58 +02001343 if (wl1271_set_block_size(wl))
1344 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001345 break;
1346 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001348 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001349 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001350 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001351 }
1352
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001353 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001354 ret = wl1271_fetch_firmware(wl);
1355 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001356 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357 }
1358
1359 /* No NVS from netlink, try to get it from the filesystem */
1360 if (wl->nvs == NULL) {
1361 ret = wl1271_fetch_nvs(wl);
1362 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001363 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364 }
1365
1366out:
1367 return ret;
1368}
1369
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370int wl1271_plt_start(struct wl1271 *wl)
1371{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001372 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001373 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001374 int ret;
1375
1376 mutex_lock(&wl->mutex);
1377
1378 wl1271_notice("power up");
1379
1380 if (wl->state != WL1271_STATE_OFF) {
1381 wl1271_error("cannot go into PLT state because not "
1382 "in off state: %d", wl->state);
1383 ret = -EBUSY;
1384 goto out;
1385 }
1386
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001387 while (retries) {
1388 retries--;
1389 ret = wl1271_chip_wakeup(wl);
1390 if (ret < 0)
1391 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001392
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001393 ret = wl1271_boot(wl);
1394 if (ret < 0)
1395 goto power_off;
1396
1397 ret = wl1271_plt_init(wl);
1398 if (ret < 0)
1399 goto irq_disable;
1400
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001401 wl->state = WL1271_STATE_PLT;
1402 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001403 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001404
Gery Kahn6f07b722011-07-18 14:21:49 +03001405 /* update hw/fw version info in wiphy struct */
1406 wiphy->hw_version = wl->chip.id;
1407 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1408 sizeof(wiphy->fw_version));
1409
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001410 goto out;
1411
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001412irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001413 mutex_unlock(&wl->mutex);
1414 /* Unlocking the mutex in the middle of handling is
1415 inherently unsafe. In this case we deem it safe to do,
1416 because we need to let any possibly pending IRQ out of
1417 the system (and while we are WL1271_STATE_OFF the IRQ
1418 work function will not do anything.) Also, any other
1419 possible concurrent operations will fail due to the
1420 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001421 wl1271_disable_interrupts(wl);
1422 wl1271_flush_deferred_work(wl);
1423 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001424 mutex_lock(&wl->mutex);
1425power_off:
1426 wl1271_power_off(wl);
1427 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001428
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001429 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1430 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001431out:
1432 mutex_unlock(&wl->mutex);
1433
1434 return ret;
1435}
1436
Luciano Coelho4623ec72011-03-21 19:26:41 +02001437static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438{
1439 int ret = 0;
1440
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441 wl1271_notice("power down");
1442
1443 if (wl->state != WL1271_STATE_PLT) {
1444 wl1271_error("cannot power down because not in PLT "
1445 "state: %d", wl->state);
1446 ret = -EBUSY;
1447 goto out;
1448 }
1449
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001450 wl1271_power_off(wl);
1451
1452 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001453 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001456 wl1271_disable_interrupts(wl);
1457 wl1271_flush_deferred_work(wl);
1458 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001459 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001460 mutex_lock(&wl->mutex);
1461out:
1462 return ret;
1463}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001464
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001465int wl1271_plt_stop(struct wl1271 *wl)
1466{
1467 int ret;
1468
1469 mutex_lock(&wl->mutex);
1470 ret = __wl1271_plt_stop(wl);
1471 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001472 return ret;
1473}
1474
Johannes Berg7bb45682011-02-24 14:42:06 +01001475static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001476{
1477 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001478 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1479 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001480 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001481 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001482 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001483 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001484
Eliad Peller0f168012011-10-11 13:52:25 +02001485 if (vif)
1486 wlvif = wl12xx_vif_to_data(vif);
1487
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001488 mapping = skb_get_queue_mapping(skb);
1489 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001490
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001491 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001492
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001493 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001494
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001495 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001496 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001497 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001498 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
1499 dev_kfree_skb(skb);
1500 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001501 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001502
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001503 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1504 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1505
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001506 wl->tx_queue_count[q]++;
1507
1508 /*
1509 * The workqueue is slow to process the tx_queue and we need stop
1510 * the queue here, otherwise the queue will get too long.
1511 */
1512 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1513 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1514 ieee80211_stop_queue(wl->hw, mapping);
1515 set_bit(q, &wl->stopped_queues_map);
1516 }
1517
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001518 /*
1519 * The chip specific setup must run before the first TX packet -
1520 * before that, the tx_work will not be initialized!
1521 */
1522
Ido Yarivb07d4032011-03-01 15:14:43 +02001523 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1524 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001525 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001526
Arik Nemtsov04216da2011-08-14 13:17:38 +03001527out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001528 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001529}
1530
Shahar Leviae47c452011-03-06 16:32:14 +02001531int wl1271_tx_dummy_packet(struct wl1271 *wl)
1532{
Ido Yariv990f5de2011-03-31 10:06:59 +02001533 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001534 int q;
1535
1536 /* no need to queue a new dummy packet if one is already pending */
1537 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1538 return 0;
1539
1540 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001541
Ido Yariv990f5de2011-03-31 10:06:59 +02001542 spin_lock_irqsave(&wl->wl_lock, flags);
1543 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001544 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001545 spin_unlock_irqrestore(&wl->wl_lock, flags);
1546
1547 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1548 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001549 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001550
1551 /*
1552 * If the FW TX is busy, TX work will be scheduled by the threaded
1553 * interrupt handler function
1554 */
1555 return 0;
1556}
1557
1558/*
1559 * The size of the dummy packet should be at least 1400 bytes. However, in
1560 * order to minimize the number of bus transactions, aligning it to 512 bytes
1561 * boundaries could be beneficial, performance wise
1562 */
1563#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1564
Luciano Coelhocf27d862011-04-01 21:08:23 +03001565static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001566{
1567 struct sk_buff *skb;
1568 struct ieee80211_hdr_3addr *hdr;
1569 unsigned int dummy_packet_size;
1570
1571 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1572 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1573
1574 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001575 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001576 wl1271_warning("Failed to allocate a dummy packet skb");
1577 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001578 }
1579
1580 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1581
1582 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1583 memset(hdr, 0, sizeof(*hdr));
1584 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001585 IEEE80211_STYPE_NULLFUNC |
1586 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001587
Ido Yariv990f5de2011-03-31 10:06:59 +02001588 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001589
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001590 /* Dummy packets require the TID to be management */
1591 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001592
1593 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001594 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001595 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001596
Ido Yariv990f5de2011-03-31 10:06:59 +02001597 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001598}
1599
Ido Yariv990f5de2011-03-31 10:06:59 +02001600
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001601static struct notifier_block wl1271_dev_notifier = {
1602 .notifier_call = wl1271_dev_notify,
1603};
1604
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001605#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001606static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1607 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001608{
Eliad Pellere85d1622011-06-27 13:06:43 +03001609 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001610
Eliad Peller94390642011-05-13 11:57:13 +03001611 mutex_lock(&wl->mutex);
1612
Eliad Pellerba8447f2011-10-10 10:13:00 +02001613 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001614 goto out_unlock;
1615
Eliad Peller94390642011-05-13 11:57:13 +03001616 ret = wl1271_ps_elp_wakeup(wl);
1617 if (ret < 0)
1618 goto out_unlock;
1619
1620 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001621 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001622 DECLARE_COMPLETION_ONSTACK(compl);
1623
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001624 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001625 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001626 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001627 if (ret < 0)
1628 goto out_sleep;
1629
1630 /* we must unlock here so we will be able to get events */
1631 wl1271_ps_elp_sleep(wl);
1632 mutex_unlock(&wl->mutex);
1633
1634 ret = wait_for_completion_timeout(
1635 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1636 if (ret <= 0) {
1637 wl1271_warning("couldn't enter ps mode!");
1638 ret = -EBUSY;
1639 goto out;
1640 }
1641
1642 /* take mutex again, and wakeup */
1643 mutex_lock(&wl->mutex);
1644
1645 ret = wl1271_ps_elp_wakeup(wl);
1646 if (ret < 0)
1647 goto out_unlock;
1648 }
1649out_sleep:
1650 wl1271_ps_elp_sleep(wl);
1651out_unlock:
1652 mutex_unlock(&wl->mutex);
1653out:
1654 return ret;
1655
1656}
1657
Eliad Peller0603d892011-10-05 11:55:51 +02001658static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1659 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001660{
Eliad Pellere85d1622011-06-27 13:06:43 +03001661 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001662
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001663 mutex_lock(&wl->mutex);
1664
Eliad Peller53d40d02011-10-10 10:13:02 +02001665 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001666 goto out_unlock;
1667
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001668 ret = wl1271_ps_elp_wakeup(wl);
1669 if (ret < 0)
1670 goto out_unlock;
1671
Eliad Peller0603d892011-10-05 11:55:51 +02001672 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001673
1674 wl1271_ps_elp_sleep(wl);
1675out_unlock:
1676 mutex_unlock(&wl->mutex);
1677 return ret;
1678
1679}
1680
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001681static int wl1271_configure_suspend(struct wl1271 *wl,
1682 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001683{
Eliad Peller536129c2011-10-05 11:55:45 +02001684 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001685 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001686 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001687 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001688 return 0;
1689}
1690
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001691static void wl1271_configure_resume(struct wl1271 *wl,
1692 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001693{
1694 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001695 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1696 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001697
1698 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001699 return;
1700
1701 mutex_lock(&wl->mutex);
1702 ret = wl1271_ps_elp_wakeup(wl);
1703 if (ret < 0)
1704 goto out;
1705
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001706 if (is_sta) {
1707 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001708 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001709 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001710 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001711 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001712 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001713 }
Eliad Peller94390642011-05-13 11:57:13 +03001714
1715 wl1271_ps_elp_sleep(wl);
1716out:
1717 mutex_unlock(&wl->mutex);
1718}
1719
Eliad Peller402e48612011-05-13 11:57:09 +03001720static int wl1271_op_suspend(struct ieee80211_hw *hw,
1721 struct cfg80211_wowlan *wow)
1722{
1723 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001724 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001725 int ret;
1726
Eliad Peller402e48612011-05-13 11:57:09 +03001727 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001728 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001729
Eliad Peller4a859df2011-06-06 12:21:52 +03001730 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001731 wl12xx_for_each_wlvif(wl, wlvif) {
1732 ret = wl1271_configure_suspend(wl, wlvif);
1733 if (ret < 0) {
1734 wl1271_warning("couldn't prepare device to suspend");
1735 return ret;
1736 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001737 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001738 /* flush any remaining work */
1739 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001740
1741 /*
1742 * disable and re-enable interrupts in order to flush
1743 * the threaded_irq
1744 */
1745 wl1271_disable_interrupts(wl);
1746
1747 /*
1748 * set suspended flag to avoid triggering a new threaded_irq
1749 * work. no need for spinlock as interrupts are disabled.
1750 */
1751 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1752
1753 wl1271_enable_interrupts(wl);
1754 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001755 wl12xx_for_each_wlvif(wl, wlvif) {
1756 flush_delayed_work(&wlvif->pspoll_work);
1757 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001758 flush_delayed_work(&wl->elp_work);
1759
Eliad Peller402e48612011-05-13 11:57:09 +03001760 return 0;
1761}
1762
1763static int wl1271_op_resume(struct ieee80211_hw *hw)
1764{
1765 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001766 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001767 unsigned long flags;
1768 bool run_irq_work = false;
1769
Eliad Peller402e48612011-05-13 11:57:09 +03001770 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1771 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001772 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001773
1774 /*
1775 * re-enable irq_work enqueuing, and call irq_work directly if
1776 * there is a pending work.
1777 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001778 spin_lock_irqsave(&wl->wl_lock, flags);
1779 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1780 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1781 run_irq_work = true;
1782 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001783
Eliad Peller4a859df2011-06-06 12:21:52 +03001784 if (run_irq_work) {
1785 wl1271_debug(DEBUG_MAC80211,
1786 "run postponed irq_work directly");
1787 wl1271_irq(0, wl);
1788 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001789 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001790 wl12xx_for_each_wlvif(wl, wlvif) {
1791 wl1271_configure_resume(wl, wlvif);
1792 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001793 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001794
Eliad Peller402e48612011-05-13 11:57:09 +03001795 return 0;
1796}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001797#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001798
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001799static int wl1271_op_start(struct ieee80211_hw *hw)
1800{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001801 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1802
1803 /*
1804 * We have to delay the booting of the hardware because
1805 * we need to know the local MAC address before downloading and
1806 * initializing the firmware. The MAC address cannot be changed
1807 * after boot, and without the proper MAC address, the firmware
1808 * will not function properly.
1809 *
1810 * The MAC address is first known when the corresponding interface
1811 * is added. That is where we will initialize the hardware.
1812 */
1813
1814 return 0;
1815}
1816
1817static void wl1271_op_stop(struct ieee80211_hw *hw)
1818{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001819 struct wl1271 *wl = hw->priv;
1820 int i;
1821
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001822 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001823
Eliad Peller10c8cd02011-10-10 10:13:06 +02001824 mutex_lock(&wl->mutex);
1825 if (wl->state == WL1271_STATE_OFF) {
1826 mutex_unlock(&wl->mutex);
1827 return;
1828 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001829 /*
1830 * this must be before the cancel_work calls below, so that the work
1831 * functions don't perform further work.
1832 */
1833 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001834 mutex_unlock(&wl->mutex);
1835
1836 mutex_lock(&wl_list_mutex);
1837 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001838 mutex_unlock(&wl_list_mutex);
1839
1840 wl1271_disable_interrupts(wl);
1841 wl1271_flush_deferred_work(wl);
1842 cancel_delayed_work_sync(&wl->scan_complete_work);
1843 cancel_work_sync(&wl->netstack_work);
1844 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001845 cancel_delayed_work_sync(&wl->elp_work);
1846
1847 /* let's notify MAC80211 about the remaining pending TX frames */
1848 wl12xx_tx_reset(wl, true);
1849 mutex_lock(&wl->mutex);
1850
1851 wl1271_power_off(wl);
1852
1853 wl->band = IEEE80211_BAND_2GHZ;
1854
1855 wl->rx_counter = 0;
1856 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1857 wl->tx_blocks_available = 0;
1858 wl->tx_allocated_blocks = 0;
1859 wl->tx_results_count = 0;
1860 wl->tx_packets_count = 0;
1861 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001862 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1863 wl->ap_fw_ps_map = 0;
1864 wl->ap_ps_map = 0;
1865 wl->sched_scanning = false;
1866 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1867 memset(wl->links_map, 0, sizeof(wl->links_map));
1868 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1869 wl->active_sta_count = 0;
1870
1871 /* The system link is always allocated */
1872 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1873
1874 /*
1875 * this is performed after the cancel_work calls and the associated
1876 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1877 * get executed before all these vars have been reset.
1878 */
1879 wl->flags = 0;
1880
1881 wl->tx_blocks_freed = 0;
1882
1883 for (i = 0; i < NUM_TX_QUEUES; i++) {
1884 wl->tx_pkts_freed[i] = 0;
1885 wl->tx_allocated_pkts[i] = 0;
1886 }
1887
1888 wl1271_debugfs_reset(wl);
1889
1890 kfree(wl->fw_status);
1891 wl->fw_status = NULL;
1892 kfree(wl->tx_res_if);
1893 wl->tx_res_if = NULL;
1894 kfree(wl->target_mem_map);
1895 wl->target_mem_map = NULL;
1896
1897 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001898}
1899
Eliad Pellere5a359f2011-10-10 10:13:15 +02001900static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1901{
1902 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1903 WL12XX_MAX_RATE_POLICIES);
1904 if (policy >= WL12XX_MAX_RATE_POLICIES)
1905 return -EBUSY;
1906
1907 __set_bit(policy, wl->rate_policies_map);
1908 *idx = policy;
1909 return 0;
1910}
1911
1912static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1913{
1914 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1915 return;
1916
1917 __clear_bit(*idx, wl->rate_policies_map);
1918 *idx = WL12XX_MAX_RATE_POLICIES;
1919}
1920
Eliad Peller536129c2011-10-05 11:55:45 +02001921static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001922{
Eliad Peller536129c2011-10-05 11:55:45 +02001923 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001924 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001925 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001926 return WL1271_ROLE_P2P_GO;
1927 else
1928 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001929
1930 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001931 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001932 return WL1271_ROLE_P2P_CL;
1933 else
1934 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001935
Eliad Peller227e81e2011-08-14 13:17:26 +03001936 case BSS_TYPE_IBSS:
1937 return WL1271_ROLE_IBSS;
1938
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001939 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001940 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001941 }
1942 return WL12XX_INVALID_ROLE_TYPE;
1943}
1944
Eliad Peller83587502011-10-10 10:12:53 +02001945static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001946{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001947 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001948 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001949
Eliad Peller48e93e42011-10-10 10:12:58 +02001950 /* clear everything but the persistent data */
1951 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001952
1953 switch (ieee80211_vif_type_p2p(vif)) {
1954 case NL80211_IFTYPE_P2P_CLIENT:
1955 wlvif->p2p = 1;
1956 /* fall-through */
1957 case NL80211_IFTYPE_STATION:
1958 wlvif->bss_type = BSS_TYPE_STA_BSS;
1959 break;
1960 case NL80211_IFTYPE_ADHOC:
1961 wlvif->bss_type = BSS_TYPE_IBSS;
1962 break;
1963 case NL80211_IFTYPE_P2P_GO:
1964 wlvif->p2p = 1;
1965 /* fall-through */
1966 case NL80211_IFTYPE_AP:
1967 wlvif->bss_type = BSS_TYPE_AP_BSS;
1968 break;
1969 default:
1970 wlvif->bss_type = MAX_BSS_TYPE;
1971 return -EOPNOTSUPP;
1972 }
1973
Eliad Peller0603d892011-10-05 11:55:51 +02001974 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001975 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001976 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001977
Eliad Pellere936bbe2011-10-05 11:55:56 +02001978 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1979 wlvif->bss_type == BSS_TYPE_IBSS) {
1980 /* init sta/ibss data */
1981 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001982 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1983 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1984 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001985 } else {
1986 /* init ap data */
1987 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1988 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001989 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1990 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1991 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1992 wl12xx_allocate_rate_policy(wl,
1993 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001994 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001995
Eliad Peller83587502011-10-10 10:12:53 +02001996 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1997 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001998 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001999 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002000 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02002001 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
2002
Eliad Peller1b92f152011-10-10 10:13:09 +02002003 /*
2004 * mac80211 configures some values globally, while we treat them
2005 * per-interface. thus, on init, we have to copy them from wl
2006 */
2007 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02002008 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02002009 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02002010
Eliad Peller9eb599e2011-10-10 10:12:59 +02002011 INIT_WORK(&wlvif->rx_streaming_enable_work,
2012 wl1271_rx_streaming_enable_work);
2013 INIT_WORK(&wlvif->rx_streaming_disable_work,
2014 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02002015 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02002016 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02002017
Eliad Peller9eb599e2011-10-10 10:12:59 +02002018 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
2019 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002020 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002021}
2022
Eliad Peller1d095472011-10-10 10:12:49 +02002023static bool wl12xx_init_fw(struct wl1271 *wl)
2024{
2025 int retries = WL1271_BOOT_RETRIES;
2026 bool booted = false;
2027 struct wiphy *wiphy = wl->hw->wiphy;
2028 int ret;
2029
2030 while (retries) {
2031 retries--;
2032 ret = wl1271_chip_wakeup(wl);
2033 if (ret < 0)
2034 goto power_off;
2035
2036 ret = wl1271_boot(wl);
2037 if (ret < 0)
2038 goto power_off;
2039
2040 ret = wl1271_hw_init(wl);
2041 if (ret < 0)
2042 goto irq_disable;
2043
2044 booted = true;
2045 break;
2046
2047irq_disable:
2048 mutex_unlock(&wl->mutex);
2049 /* Unlocking the mutex in the middle of handling is
2050 inherently unsafe. In this case we deem it safe to do,
2051 because we need to let any possibly pending IRQ out of
2052 the system (and while we are WL1271_STATE_OFF the IRQ
2053 work function will not do anything.) Also, any other
2054 possible concurrent operations will fail due to the
2055 current state, hence the wl1271 struct should be safe. */
2056 wl1271_disable_interrupts(wl);
2057 wl1271_flush_deferred_work(wl);
2058 cancel_work_sync(&wl->netstack_work);
2059 mutex_lock(&wl->mutex);
2060power_off:
2061 wl1271_power_off(wl);
2062 }
2063
2064 if (!booted) {
2065 wl1271_error("firmware boot failed despite %d retries",
2066 WL1271_BOOT_RETRIES);
2067 goto out;
2068 }
2069
2070 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2071
2072 /* update hw/fw version info in wiphy struct */
2073 wiphy->hw_version = wl->chip.id;
2074 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2075 sizeof(wiphy->fw_version));
2076
2077 /*
2078 * Now we know if 11a is supported (info from the NVS), so disable
2079 * 11a channels if not supported
2080 */
2081 if (!wl->enable_11a)
2082 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2083
2084 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2085 wl->enable_11a ? "" : "not ");
2086
2087 wl->state = WL1271_STATE_ON;
2088out:
2089 return booted;
2090}
2091
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002092static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2093 struct ieee80211_vif *vif)
2094{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002095 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002096 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002097 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002098 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002099 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002100
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002101 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002102 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002103
2104 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002105 ret = wl1271_ps_elp_wakeup(wl);
2106 if (ret < 0)
2107 goto out_unlock;
2108
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002109 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002110 wl1271_debug(DEBUG_MAC80211,
2111 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002112 ret = -EBUSY;
2113 goto out;
2114 }
2115
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002116 /*
2117 * in some very corner case HW recovery scenarios its possible to
2118 * get here before __wl1271_op_remove_interface is complete, so
2119 * opt out if that is the case.
2120 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002121 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2122 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002123 ret = -EBUSY;
2124 goto out;
2125 }
2126
Eliad Peller83587502011-10-10 10:12:53 +02002127 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002128 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002129 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002130
Eliad Peller252efa42011-10-05 11:56:00 +02002131 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002132 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002133 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2134 ret = -EINVAL;
2135 goto out;
2136 }
Eliad Peller1d095472011-10-10 10:12:49 +02002137
Eliad Peller784f6942011-10-05 11:55:39 +02002138 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002139 * TODO: after the nvs issue will be solved, move this block
2140 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002141 */
Eliad Peller1d095472011-10-10 10:12:49 +02002142 if (wl->state == WL1271_STATE_OFF) {
2143 /*
2144 * we still need this in order to configure the fw
2145 * while uploading the nvs
2146 */
2147 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002148
Eliad Peller1d095472011-10-10 10:12:49 +02002149 booted = wl12xx_init_fw(wl);
2150 if (!booted) {
2151 ret = -EINVAL;
2152 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002153 }
Eliad Peller1d095472011-10-10 10:12:49 +02002154 }
Eliad Peller04e80792011-08-14 13:17:09 +03002155
Eliad Peller1d095472011-10-10 10:12:49 +02002156 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2157 wlvif->bss_type == BSS_TYPE_IBSS) {
2158 /*
2159 * The device role is a special role used for
2160 * rx and tx frames prior to association (as
2161 * the STA role can get packets only from
2162 * its associated bssid)
2163 */
Eliad Peller784f6942011-10-05 11:55:39 +02002164 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002165 WL1271_ROLE_DEVICE,
2166 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002167 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002168 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002169 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002170
Eliad Peller1d095472011-10-10 10:12:49 +02002171 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2172 role_type, &wlvif->role_id);
2173 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002174 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002175
2176 ret = wl1271_init_vif_specific(wl, vif);
2177 if (ret < 0)
2178 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002179
2180 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002181 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002182 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002183
2184 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2185 wl->ap_count++;
2186 else
2187 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002188out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002189 wl1271_ps_elp_sleep(wl);
2190out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002191 mutex_unlock(&wl->mutex);
2192
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002193 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002194 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002195 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002196 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002197
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002198 return ret;
2199}
2200
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002201static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002202 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002203 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002204{
Eliad Peller536129c2011-10-05 11:55:45 +02002205 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002206 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002207
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002208 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002209
Eliad Peller10c8cd02011-10-10 10:13:06 +02002210 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2211 return;
2212
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002213 wl->vif = NULL;
2214
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002215 /* because of hardware recovery, we may get here twice */
2216 if (wl->state != WL1271_STATE_ON)
2217 return;
2218
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002219 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002220
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002221 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002222 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002223 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002224
Eliad Pellerbaf62772011-10-10 10:12:52 +02002225 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2226 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002227 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002228 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002229 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002230 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002231 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002232 }
2233
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002234 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2235 /* disable active roles */
2236 ret = wl1271_ps_elp_wakeup(wl);
2237 if (ret < 0)
2238 goto deinit;
2239
Eliad Peller536129c2011-10-05 11:55:45 +02002240 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002241 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002242 if (ret < 0)
2243 goto deinit;
2244 }
2245
Eliad Peller0603d892011-10-05 11:55:51 +02002246 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002247 if (ret < 0)
2248 goto deinit;
2249
2250 wl1271_ps_elp_sleep(wl);
2251 }
2252deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002253 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002254 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002255
2256 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2257 wlvif->bss_type == BSS_TYPE_IBSS) {
2258 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2259 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2260 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2261 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2262 } else {
2263 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2264 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2265 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2266 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2267 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2268 wl12xx_free_rate_policy(wl,
2269 &wlvif->ap.ucast_rate_idx[i]);
2270 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002271
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002272 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002273 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002274 if (wl->last_wlvif == wlvif)
2275 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002276 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002277 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002278 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002279 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002280
Eliad Pellera4e41302011-10-11 11:49:15 +02002281 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2282 wl->ap_count--;
2283 else
2284 wl->sta_count--;
2285
Eliad Pellerbaf62772011-10-10 10:12:52 +02002286 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002287 del_timer_sync(&wlvif->rx_streaming_timer);
2288 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2289 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002290 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002291
Eliad Pellerbaf62772011-10-10 10:12:52 +02002292 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002293}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002294
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002295static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2296 struct ieee80211_vif *vif)
2297{
2298 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002299 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002300 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002301
2302 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002303
2304 if (wl->state == WL1271_STATE_OFF ||
2305 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2306 goto out;
2307
Juuso Oikarinen67353292010-11-18 15:19:02 +02002308 /*
2309 * wl->vif can be null here if someone shuts down the interface
2310 * just when hardware recovery has been started.
2311 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002312 wl12xx_for_each_wlvif(wl, iter) {
2313 if (iter != wlvif)
2314 continue;
2315
Eliad Peller536129c2011-10-05 11:55:45 +02002316 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002317 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002318 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002319 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002320out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002321 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002322 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002323}
2324
Eliad Peller87fbcb02011-10-05 11:55:41 +02002325static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2326 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002327{
2328 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002329 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002330
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002331 /*
2332 * One of the side effects of the JOIN command is that is clears
2333 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2334 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002335 * Currently the only valid scenario for JOIN during association
2336 * is on roaming, in which case we will also be given new keys.
2337 * Keep the below message for now, unless it starts bothering
2338 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002339 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002340 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002341 wl1271_info("JOIN while associated.");
2342
2343 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002344 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002345
Eliad Peller227e81e2011-08-14 13:17:26 +03002346 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002347 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002348 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002349 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002350 if (ret < 0)
2351 goto out;
2352
Eliad Pellerba8447f2011-10-10 10:13:00 +02002353 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002354 goto out;
2355
2356 /*
2357 * The join command disable the keep-alive mode, shut down its process,
2358 * and also clear the template config, so we need to reset it all after
2359 * the join. The acx_aid starts the keep-alive process, and the order
2360 * of the commands below is relevant.
2361 */
Eliad Peller0603d892011-10-05 11:55:51 +02002362 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002363 if (ret < 0)
2364 goto out;
2365
Eliad Peller0603d892011-10-05 11:55:51 +02002366 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002367 if (ret < 0)
2368 goto out;
2369
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002370 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002371 if (ret < 0)
2372 goto out;
2373
Eliad Peller0603d892011-10-05 11:55:51 +02002374 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2375 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002376 ACX_KEEP_ALIVE_TPL_VALID);
2377 if (ret < 0)
2378 goto out;
2379
2380out:
2381 return ret;
2382}
2383
Eliad Peller0603d892011-10-05 11:55:51 +02002384static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002385{
2386 int ret;
2387
Eliad Peller52630c52011-10-10 10:13:08 +02002388 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002389 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2390
Shahar Levi6d158ff2011-09-08 13:01:33 +03002391 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002392 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002393 }
2394
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002395 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002396 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002397 if (ret < 0)
2398 goto out;
2399
Oz Krakowskib992c682011-06-26 10:36:02 +03002400 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002401 wlvif->tx_security_last_seq_lsb = 0;
2402 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002403
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002404out:
2405 return ret;
2406}
2407
Eliad Peller87fbcb02011-10-05 11:55:41 +02002408static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002409{
Eliad Peller1b92f152011-10-10 10:13:09 +02002410 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002411 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002412}
2413
Eliad Peller251c1772011-08-14 13:17:17 +03002414static bool wl12xx_is_roc(struct wl1271 *wl)
2415{
2416 u8 role_id;
2417
2418 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2419 if (role_id >= WL12XX_MAX_ROLES)
2420 return false;
2421
2422 return true;
2423}
2424
Eliad Peller87fbcb02011-10-05 11:55:41 +02002425static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2426 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002427{
2428 int ret;
2429
2430 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002431 /* no need to croc if we weren't busy (e.g. during boot) */
2432 if (wl12xx_is_roc(wl)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002433 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002434 if (ret < 0)
2435 goto out;
2436 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002437 wlvif->rate_set =
2438 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2439 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002440 if (ret < 0)
2441 goto out;
2442 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002443 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002444 ACX_KEEP_ALIVE_TPL_INVALID);
2445 if (ret < 0)
2446 goto out;
2447 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2448 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002449 /* The current firmware only supports sched_scan in idle */
2450 if (wl->sched_scanning) {
2451 wl1271_scan_sched_scan_stop(wl);
2452 ieee80211_sched_scan_stopped(wl->hw);
2453 }
2454
Eliad Peller679a6732011-10-11 11:55:44 +02002455 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002456 if (ret < 0)
2457 goto out;
2458 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2459 }
2460
2461out:
2462 return ret;
2463}
2464
Eliad Peller9f259c42011-10-10 10:13:12 +02002465static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2466 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002467{
Eliad Peller9f259c42011-10-10 10:13:12 +02002468 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2469 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002470
2471 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2472
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002473 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002474 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002475 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002476 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002477 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002478 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002479 wlvif->band = conf->channel->band;
2480 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002481
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002482 if (!is_ap) {
2483 /*
2484 * FIXME: the mac80211 should really provide a fixed
2485 * rate to use here. for now, just use the smallest
2486 * possible rate for the band as a fixed rate for
2487 * association frames and other control messages.
2488 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002489 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002490 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002491
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002492 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002493 wl1271_tx_min_rate_get(wl,
2494 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002495 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002496 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002497 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002498 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002499
Eliad Pellerba8447f2011-10-10 10:13:00 +02002500 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2501 &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002502 if (wl12xx_is_roc(wl)) {
2503 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002504 ret = wl12xx_croc(wl,
2505 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002506 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002507 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002508 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002509 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002510 if (ret < 0)
2511 wl1271_warning("cmd join on channel "
2512 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002513 } else {
2514 /*
2515 * change the ROC channel. do it only if we are
2516 * not idle. otherwise, CROC will be called
2517 * anyway.
2518 */
2519 if (wl12xx_is_roc(wl) &&
2520 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002521 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002522 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002523 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002524
Eliad Peller679a6732011-10-11 11:55:44 +02002525 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002526 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002527 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002528 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002529 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002530 }
2531 }
2532
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002533 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002534 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002535 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002536 if (ret < 0)
2537 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002538 }
2539
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002540 /*
2541 * if mac80211 changes the PSM mode, make sure the mode is not
2542 * incorrectly changed after the pspoll failure active window.
2543 */
2544 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002545 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002546
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002547 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002548 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2549 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002550
2551 /*
2552 * We enter PSM only if we're already associated.
2553 * If we're not, we'll enter it when joining an SSID,
2554 * through the bss_info_changed() hook.
2555 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002556 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002557 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002558 ret = wl1271_ps_set_mode(wl, wlvif,
2559 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002560 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002561 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002562 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002563 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002564 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002565
Eliad Pellerc29bb002011-10-10 10:13:03 +02002566 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002567
Eliad Pellerc29bb002011-10-10 10:13:03 +02002568 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002569 ret = wl1271_ps_set_mode(wl, wlvif,
2570 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002571 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002572 }
2573
Eliad Peller6bd65022011-10-10 10:13:11 +02002574 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002575 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002576 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002577 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002578
Eliad Peller6bd65022011-10-10 10:13:11 +02002579 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002580 }
2581
Eliad Peller9f259c42011-10-10 10:13:12 +02002582 return 0;
2583}
2584
2585static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2586{
2587 struct wl1271 *wl = hw->priv;
2588 struct wl12xx_vif *wlvif;
2589 struct ieee80211_conf *conf = &hw->conf;
2590 int channel, ret = 0;
2591
2592 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2593
2594 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2595 " changed 0x%x",
2596 channel,
2597 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2598 conf->power_level,
2599 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2600 changed);
2601
2602 /*
2603 * mac80211 will go to idle nearly immediately after transmitting some
2604 * frames, such as the deauth. To make sure those frames reach the air,
2605 * wait here until the TX queue is fully flushed.
2606 */
2607 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2608 (conf->flags & IEEE80211_CONF_IDLE))
2609 wl1271_tx_flush(wl);
2610
2611 mutex_lock(&wl->mutex);
2612
2613 /* we support configuring the channel and band even while off */
2614 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2615 wl->band = conf->channel->band;
2616 wl->channel = channel;
2617 }
2618
2619 if (changed & IEEE80211_CONF_CHANGE_POWER)
2620 wl->power_level = conf->power_level;
2621
2622 if (unlikely(wl->state == WL1271_STATE_OFF))
2623 goto out;
2624
2625 ret = wl1271_ps_elp_wakeup(wl);
2626 if (ret < 0)
2627 goto out;
2628
2629 /* configure each interface */
2630 wl12xx_for_each_wlvif(wl, wlvif) {
2631 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2632 if (ret < 0)
2633 goto out_sleep;
2634 }
2635
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002636out_sleep:
2637 wl1271_ps_elp_sleep(wl);
2638
2639out:
2640 mutex_unlock(&wl->mutex);
2641
2642 return ret;
2643}
2644
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002645struct wl1271_filter_params {
2646 bool enabled;
2647 int mc_list_length;
2648 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2649};
2650
Jiri Pirko22bedad2010-04-01 21:22:57 +00002651static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2652 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002653{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002654 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002655 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002656 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002657
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002658 if (unlikely(wl->state == WL1271_STATE_OFF))
2659 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002660
Juuso Oikarinen74441132009-10-13 12:47:53 +03002661 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002662 if (!fp) {
2663 wl1271_error("Out of memory setting filters.");
2664 return 0;
2665 }
2666
2667 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002668 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002669 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2670 fp->enabled = false;
2671 } else {
2672 fp->enabled = true;
2673 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002674 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002675 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002676 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002677 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002678 }
2679
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002680 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002681}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002682
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002683#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2684 FIF_ALLMULTI | \
2685 FIF_FCSFAIL | \
2686 FIF_BCN_PRBRESP_PROMISC | \
2687 FIF_CONTROL | \
2688 FIF_OTHER_BSS)
2689
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002690static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2691 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002692 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002693{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002694 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002695 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002696 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002697
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002698 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002699
Arik Nemtsov7d057862010-10-16 19:25:35 +02002700 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2701 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002702
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002703 mutex_lock(&wl->mutex);
2704
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002705 *total &= WL1271_SUPPORTED_FILTERS;
2706 changed &= WL1271_SUPPORTED_FILTERS;
2707
2708 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002709 goto out;
2710
Ido Yariva6208652011-03-01 15:14:41 +02002711 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002712 if (ret < 0)
2713 goto out;
2714
Eliad Peller6e8cd332011-10-10 10:13:13 +02002715 wl12xx_for_each_wlvif(wl, wlvif) {
2716 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2717 if (*total & FIF_ALLMULTI)
2718 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2719 false,
2720 NULL, 0);
2721 else if (fp)
2722 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2723 fp->enabled,
2724 fp->mc_list,
2725 fp->mc_list_length);
2726 if (ret < 0)
2727 goto out_sleep;
2728 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002729 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002730
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002731 /*
2732 * the fw doesn't provide an api to configure the filters. instead,
2733 * the filters configuration is based on the active roles / ROC
2734 * state.
2735 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002736
2737out_sleep:
2738 wl1271_ps_elp_sleep(wl);
2739
2740out:
2741 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002742 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002743}
2744
Eliad Peller170d0e62011-10-05 11:56:06 +02002745static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2746 u8 id, u8 key_type, u8 key_size,
2747 const u8 *key, u8 hlid, u32 tx_seq_32,
2748 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002749{
2750 struct wl1271_ap_key *ap_key;
2751 int i;
2752
2753 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2754
2755 if (key_size > MAX_KEY_SIZE)
2756 return -EINVAL;
2757
2758 /*
2759 * Find next free entry in ap_keys. Also check we are not replacing
2760 * an existing key.
2761 */
2762 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002763 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002764 break;
2765
Eliad Peller170d0e62011-10-05 11:56:06 +02002766 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002767 wl1271_warning("trying to record key replacement");
2768 return -EINVAL;
2769 }
2770 }
2771
2772 if (i == MAX_NUM_KEYS)
2773 return -EBUSY;
2774
2775 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2776 if (!ap_key)
2777 return -ENOMEM;
2778
2779 ap_key->id = id;
2780 ap_key->key_type = key_type;
2781 ap_key->key_size = key_size;
2782 memcpy(ap_key->key, key, key_size);
2783 ap_key->hlid = hlid;
2784 ap_key->tx_seq_32 = tx_seq_32;
2785 ap_key->tx_seq_16 = tx_seq_16;
2786
Eliad Peller170d0e62011-10-05 11:56:06 +02002787 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002788 return 0;
2789}
2790
Eliad Peller170d0e62011-10-05 11:56:06 +02002791static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002792{
2793 int i;
2794
2795 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002796 kfree(wlvif->ap.recorded_keys[i]);
2797 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002798 }
2799}
2800
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002801static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002802{
2803 int i, ret = 0;
2804 struct wl1271_ap_key *key;
2805 bool wep_key_added = false;
2806
2807 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002808 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002809 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002810 break;
2811
Eliad Peller170d0e62011-10-05 11:56:06 +02002812 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002813 hlid = key->hlid;
2814 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002815 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002816
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002817 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002818 key->id, key->key_type,
2819 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002820 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002821 key->tx_seq_16);
2822 if (ret < 0)
2823 goto out;
2824
2825 if (key->key_type == KEY_WEP)
2826 wep_key_added = true;
2827 }
2828
2829 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002830 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002831 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002832 if (ret < 0)
2833 goto out;
2834 }
2835
2836out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002837 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002838 return ret;
2839}
2840
Eliad Peller536129c2011-10-05 11:55:45 +02002841static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2842 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002843 u8 key_size, const u8 *key, u32 tx_seq_32,
2844 u16 tx_seq_16, struct ieee80211_sta *sta)
2845{
2846 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002847 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002848
2849 if (is_ap) {
2850 struct wl1271_station *wl_sta;
2851 u8 hlid;
2852
2853 if (sta) {
2854 wl_sta = (struct wl1271_station *)sta->drv_priv;
2855 hlid = wl_sta->hlid;
2856 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002857 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002858 }
2859
Eliad Peller53d40d02011-10-10 10:13:02 +02002860 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002861 /*
2862 * We do not support removing keys after AP shutdown.
2863 * Pretend we do to make mac80211 happy.
2864 */
2865 if (action != KEY_ADD_OR_REPLACE)
2866 return 0;
2867
Eliad Peller170d0e62011-10-05 11:56:06 +02002868 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002869 key_type, key_size,
2870 key, hlid, tx_seq_32,
2871 tx_seq_16);
2872 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002873 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002874 id, key_type, key_size,
2875 key, hlid, tx_seq_32,
2876 tx_seq_16);
2877 }
2878
2879 if (ret < 0)
2880 return ret;
2881 } else {
2882 const u8 *addr;
2883 static const u8 bcast_addr[ETH_ALEN] = {
2884 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2885 };
2886
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002887 /*
2888 * A STA set to GEM cipher requires 2 tx spare blocks.
2889 * Return to default value when GEM cipher key is removed
2890 */
2891 if (key_type == KEY_GEM) {
2892 if (action == KEY_ADD_OR_REPLACE)
2893 wl->tx_spare_blocks = 2;
2894 else if (action == KEY_REMOVE)
2895 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2896 }
2897
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002898 addr = sta ? sta->addr : bcast_addr;
2899
2900 if (is_zero_ether_addr(addr)) {
2901 /* We dont support TX only encryption */
2902 return -EOPNOTSUPP;
2903 }
2904
2905 /* The wl1271 does not allow to remove unicast keys - they
2906 will be cleared automatically on next CMD_JOIN. Ignore the
2907 request silently, as we dont want the mac80211 to emit
2908 an error message. */
2909 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2910 return 0;
2911
Eliad Peller010d3d32011-08-14 13:17:31 +03002912 /* don't remove key if hlid was already deleted */
2913 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002914 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002915 return 0;
2916
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002917 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002918 id, key_type, key_size,
2919 key, addr, tx_seq_32,
2920 tx_seq_16);
2921 if (ret < 0)
2922 return ret;
2923
2924 /* the default WEP key needs to be configured at least once */
2925 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002926 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002927 wlvif->default_key,
2928 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002929 if (ret < 0)
2930 return ret;
2931 }
2932 }
2933
2934 return 0;
2935}
2936
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002937static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2938 struct ieee80211_vif *vif,
2939 struct ieee80211_sta *sta,
2940 struct ieee80211_key_conf *key_conf)
2941{
2942 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002943 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002944 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002945 u32 tx_seq_32 = 0;
2946 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002947 u8 key_type;
2948
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002949 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2950
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002951 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002952 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002953 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002954 key_conf->keylen, key_conf->flags);
2955 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2956
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002957 mutex_lock(&wl->mutex);
2958
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002959 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2960 ret = -EAGAIN;
2961 goto out_unlock;
2962 }
2963
Ido Yariva6208652011-03-01 15:14:41 +02002964 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002965 if (ret < 0)
2966 goto out_unlock;
2967
Johannes Berg97359d12010-08-10 09:46:38 +02002968 switch (key_conf->cipher) {
2969 case WLAN_CIPHER_SUITE_WEP40:
2970 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002971 key_type = KEY_WEP;
2972
2973 key_conf->hw_key_idx = key_conf->keyidx;
2974 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002975 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002976 key_type = KEY_TKIP;
2977
2978 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002979 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2980 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002981 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002982 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002983 key_type = KEY_AES;
2984
2985 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Eliad Peller48e93e42011-10-10 10:12:58 +02002986 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2987 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002988 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002989 case WL1271_CIPHER_SUITE_GEM:
2990 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002991 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2992 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002993 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002994 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002995 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002996
2997 ret = -EOPNOTSUPP;
2998 goto out_sleep;
2999 }
3000
3001 switch (cmd) {
3002 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003003 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003004 key_conf->keyidx, key_type,
3005 key_conf->keylen, key_conf->key,
3006 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003007 if (ret < 0) {
3008 wl1271_error("Could not add or replace key");
3009 goto out_sleep;
3010 }
3011 break;
3012
3013 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003014 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003015 key_conf->keyidx, key_type,
3016 key_conf->keylen, key_conf->key,
3017 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003018 if (ret < 0) {
3019 wl1271_error("Could not remove key");
3020 goto out_sleep;
3021 }
3022 break;
3023
3024 default:
3025 wl1271_error("Unsupported key cmd 0x%x", cmd);
3026 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003027 break;
3028 }
3029
3030out_sleep:
3031 wl1271_ps_elp_sleep(wl);
3032
3033out_unlock:
3034 mutex_unlock(&wl->mutex);
3035
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003036 return ret;
3037}
3038
3039static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003040 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003041 struct cfg80211_scan_request *req)
3042{
3043 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003044 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3045
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003046 int ret;
3047 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003048 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003049
3050 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3051
3052 if (req->n_ssids) {
3053 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003054 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003055 }
3056
3057 mutex_lock(&wl->mutex);
3058
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003059 if (wl->state == WL1271_STATE_OFF) {
3060 /*
3061 * We cannot return -EBUSY here because cfg80211 will expect
3062 * a call to ieee80211_scan_completed if we do - in this case
3063 * there won't be any call.
3064 */
3065 ret = -EAGAIN;
3066 goto out;
3067 }
3068
Ido Yariva6208652011-03-01 15:14:41 +02003069 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003070 if (ret < 0)
3071 goto out;
3072
Eliad Peller251c1772011-08-14 13:17:17 +03003073 /* cancel ROC before scanning */
3074 if (wl12xx_is_roc(wl)) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02003075 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03003076 /* don't allow scanning right now */
3077 ret = -EBUSY;
3078 goto out_sleep;
3079 }
Eliad Peller679a6732011-10-11 11:55:44 +02003080 wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003081 }
3082
Eliad Peller784f6942011-10-05 11:55:39 +02003083 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003084out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003085 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003086out:
3087 mutex_unlock(&wl->mutex);
3088
3089 return ret;
3090}
3091
Eliad Peller73ecce32011-06-27 13:06:45 +03003092static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3093 struct ieee80211_vif *vif)
3094{
3095 struct wl1271 *wl = hw->priv;
3096 int ret;
3097
3098 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3099
3100 mutex_lock(&wl->mutex);
3101
3102 if (wl->state == WL1271_STATE_OFF)
3103 goto out;
3104
3105 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3106 goto out;
3107
3108 ret = wl1271_ps_elp_wakeup(wl);
3109 if (ret < 0)
3110 goto out;
3111
3112 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3113 ret = wl1271_scan_stop(wl);
3114 if (ret < 0)
3115 goto out_sleep;
3116 }
3117 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3118 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003119 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003120 wl->scan.req = NULL;
3121 ieee80211_scan_completed(wl->hw, true);
3122
3123out_sleep:
3124 wl1271_ps_elp_sleep(wl);
3125out:
3126 mutex_unlock(&wl->mutex);
3127
3128 cancel_delayed_work_sync(&wl->scan_complete_work);
3129}
3130
Luciano Coelho33c2c062011-05-10 14:46:02 +03003131static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3132 struct ieee80211_vif *vif,
3133 struct cfg80211_sched_scan_request *req,
3134 struct ieee80211_sched_scan_ies *ies)
3135{
3136 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003137 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003138 int ret;
3139
3140 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3141
3142 mutex_lock(&wl->mutex);
3143
3144 ret = wl1271_ps_elp_wakeup(wl);
3145 if (ret < 0)
3146 goto out;
3147
Eliad Peller536129c2011-10-05 11:55:45 +02003148 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003149 if (ret < 0)
3150 goto out_sleep;
3151
Eliad Peller536129c2011-10-05 11:55:45 +02003152 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003153 if (ret < 0)
3154 goto out_sleep;
3155
3156 wl->sched_scanning = true;
3157
3158out_sleep:
3159 wl1271_ps_elp_sleep(wl);
3160out:
3161 mutex_unlock(&wl->mutex);
3162 return ret;
3163}
3164
3165static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3166 struct ieee80211_vif *vif)
3167{
3168 struct wl1271 *wl = hw->priv;
3169 int ret;
3170
3171 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3172
3173 mutex_lock(&wl->mutex);
3174
3175 ret = wl1271_ps_elp_wakeup(wl);
3176 if (ret < 0)
3177 goto out;
3178
3179 wl1271_scan_sched_scan_stop(wl);
3180
3181 wl1271_ps_elp_sleep(wl);
3182out:
3183 mutex_unlock(&wl->mutex);
3184}
3185
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003186static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3187{
3188 struct wl1271 *wl = hw->priv;
3189 int ret = 0;
3190
3191 mutex_lock(&wl->mutex);
3192
3193 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3194 ret = -EAGAIN;
3195 goto out;
3196 }
3197
Ido Yariva6208652011-03-01 15:14:41 +02003198 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003199 if (ret < 0)
3200 goto out;
3201
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003202 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003203 if (ret < 0)
3204 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3205
3206 wl1271_ps_elp_sleep(wl);
3207
3208out:
3209 mutex_unlock(&wl->mutex);
3210
3211 return ret;
3212}
3213
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003214static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3215{
3216 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003217 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003218 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003219
3220 mutex_lock(&wl->mutex);
3221
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003222 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3223 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003224 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003225 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003226
Ido Yariva6208652011-03-01 15:14:41 +02003227 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003228 if (ret < 0)
3229 goto out;
3230
Eliad Peller6e8cd332011-10-10 10:13:13 +02003231 wl12xx_for_each_wlvif(wl, wlvif) {
3232 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3233 if (ret < 0)
3234 wl1271_warning("set rts threshold failed: %d", ret);
3235 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003236 wl1271_ps_elp_sleep(wl);
3237
3238out:
3239 mutex_unlock(&wl->mutex);
3240
3241 return ret;
3242}
3243
Eliad Peller1fe9f162011-10-05 11:55:48 +02003244static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003245 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003246{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003247 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003248 u8 ssid_len;
3249 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3250 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003251
Eliad Peller889cb362011-05-01 09:56:45 +03003252 if (!ptr) {
3253 wl1271_error("No SSID in IEs!");
3254 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003255 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003256
Eliad Peller889cb362011-05-01 09:56:45 +03003257 ssid_len = ptr[1];
3258 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3259 wl1271_error("SSID is too long!");
3260 return -EINVAL;
3261 }
3262
Eliad Peller1fe9f162011-10-05 11:55:48 +02003263 wlvif->ssid_len = ssid_len;
3264 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003265 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003266}
3267
Eliad Pellerd48055d2011-09-15 12:07:04 +03003268static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3269{
3270 int len;
3271 const u8 *next, *end = skb->data + skb->len;
3272 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3273 skb->len - ieoffset);
3274 if (!ie)
3275 return;
3276 len = ie[1] + 2;
3277 next = ie + len;
3278 memmove(ie, next, end - next);
3279 skb_trim(skb, skb->len - len);
3280}
3281
Eliad Peller26b4bf22011-09-15 12:07:05 +03003282static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3283 unsigned int oui, u8 oui_type,
3284 int ieoffset)
3285{
3286 int len;
3287 const u8 *next, *end = skb->data + skb->len;
3288 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3289 skb->data + ieoffset,
3290 skb->len - ieoffset);
3291 if (!ie)
3292 return;
3293 len = ie[1] + 2;
3294 next = ie + len;
3295 memmove(ie, next, end - next);
3296 skb_trim(skb, skb->len - len);
3297}
3298
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003299static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
Eliad Peller1fe9f162011-10-05 11:55:48 +02003300 struct ieee80211_vif *vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003301 u8 *probe_rsp_data,
3302 size_t probe_rsp_len,
3303 u32 rates)
3304{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003305 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3306 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003307 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3308 int ssid_ie_offset, ie_offset, templ_len;
3309 const u8 *ptr;
3310
3311 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003312 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003313 return wl1271_cmd_template_set(wl,
3314 CMD_TEMPL_AP_PROBE_RESPONSE,
3315 probe_rsp_data,
3316 probe_rsp_len, 0,
3317 rates);
3318
3319 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3320 wl1271_error("probe_rsp template too big");
3321 return -EINVAL;
3322 }
3323
3324 /* start searching from IE offset */
3325 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3326
3327 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3328 probe_rsp_len - ie_offset);
3329 if (!ptr) {
3330 wl1271_error("No SSID in beacon!");
3331 return -EINVAL;
3332 }
3333
3334 ssid_ie_offset = ptr - probe_rsp_data;
3335 ptr += (ptr[1] + 2);
3336
3337 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3338
3339 /* insert SSID from bss_conf */
3340 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3341 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3342 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3343 bss_conf->ssid, bss_conf->ssid_len);
3344 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3345
3346 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3347 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3348 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3349
3350 return wl1271_cmd_template_set(wl,
3351 CMD_TEMPL_AP_PROBE_RESPONSE,
3352 probe_rsp_templ,
3353 templ_len, 0,
3354 rates);
3355}
3356
Arik Nemtsove78a2872010-10-16 19:07:21 +02003357static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003358 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003359 struct ieee80211_bss_conf *bss_conf,
3360 u32 changed)
3361{
Eliad Peller0603d892011-10-05 11:55:51 +02003362 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003363 int ret = 0;
3364
3365 if (changed & BSS_CHANGED_ERP_SLOT) {
3366 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003367 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003368 else
Eliad Peller0603d892011-10-05 11:55:51 +02003369 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003370 if (ret < 0) {
3371 wl1271_warning("Set slot time failed %d", ret);
3372 goto out;
3373 }
3374 }
3375
3376 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3377 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003378 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003379 else
Eliad Peller0603d892011-10-05 11:55:51 +02003380 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003381 }
3382
3383 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3384 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003385 ret = wl1271_acx_cts_protect(wl, wlvif,
3386 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003387 else
Eliad Peller0603d892011-10-05 11:55:51 +02003388 ret = wl1271_acx_cts_protect(wl, wlvif,
3389 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003390 if (ret < 0) {
3391 wl1271_warning("Set ctsprotect failed %d", ret);
3392 goto out;
3393 }
3394 }
3395
3396out:
3397 return ret;
3398}
3399
3400static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3401 struct ieee80211_vif *vif,
3402 struct ieee80211_bss_conf *bss_conf,
3403 u32 changed)
3404{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003405 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003406 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003407 int ret = 0;
3408
3409 if ((changed & BSS_CHANGED_BEACON_INT)) {
3410 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3411 bss_conf->beacon_int);
3412
Eliad Peller6a899792011-10-05 11:55:58 +02003413 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003414 }
3415
3416 if ((changed & BSS_CHANGED_BEACON)) {
3417 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003418 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003419 int ieoffset = offsetof(struct ieee80211_mgmt,
3420 u.beacon.variable);
3421 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3422 u16 tmpl_id;
3423
3424 if (!beacon)
3425 goto out;
3426
3427 wl1271_debug(DEBUG_MASTER, "beacon updated");
3428
Eliad Peller1fe9f162011-10-05 11:55:48 +02003429 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003430 if (ret < 0) {
3431 dev_kfree_skb(beacon);
3432 goto out;
3433 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003434 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003435 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3436 CMD_TEMPL_BEACON;
3437 ret = wl1271_cmd_template_set(wl, tmpl_id,
3438 beacon->data,
3439 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003440 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003441 if (ret < 0) {
3442 dev_kfree_skb(beacon);
3443 goto out;
3444 }
3445
Eliad Pellerd48055d2011-09-15 12:07:04 +03003446 /* remove TIM ie from probe response */
3447 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3448
Eliad Peller26b4bf22011-09-15 12:07:05 +03003449 /*
3450 * remove p2p ie from probe response.
3451 * the fw reponds to probe requests that don't include
3452 * the p2p ie. probe requests with p2p ie will be passed,
3453 * and will be responded by the supplicant (the spec
3454 * forbids including the p2p ie when responding to probe
3455 * requests that didn't include it).
3456 */
3457 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3458 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3459
Arik Nemtsove78a2872010-10-16 19:07:21 +02003460 hdr = (struct ieee80211_hdr *) beacon->data;
3461 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3462 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003463 if (is_ap)
Eliad Peller1fe9f162011-10-05 11:55:48 +02003464 ret = wl1271_ap_set_probe_resp_tmpl(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003465 beacon->data,
3466 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003467 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003468 else
3469 ret = wl1271_cmd_template_set(wl,
3470 CMD_TEMPL_PROBE_RESPONSE,
3471 beacon->data,
3472 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003473 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003474 dev_kfree_skb(beacon);
3475 if (ret < 0)
3476 goto out;
3477 }
3478
3479out:
3480 return ret;
3481}
3482
3483/* AP mode changes */
3484static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003485 struct ieee80211_vif *vif,
3486 struct ieee80211_bss_conf *bss_conf,
3487 u32 changed)
3488{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003489 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003490 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003491
Arik Nemtsove78a2872010-10-16 19:07:21 +02003492 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3493 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003494
Eliad Peller87fbcb02011-10-05 11:55:41 +02003495 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003496 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003497 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003498 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003499
Eliad Peller87fbcb02011-10-05 11:55:41 +02003500 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003501 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003502 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003503 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003504 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003505
Eliad Peller784f6942011-10-05 11:55:39 +02003506 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003507 if (ret < 0)
3508 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003509 }
3510
Arik Nemtsove78a2872010-10-16 19:07:21 +02003511 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3512 if (ret < 0)
3513 goto out;
3514
3515 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3516 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003517 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003518 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003519 if (ret < 0)
3520 goto out;
3521
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003522 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003523 if (ret < 0)
3524 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003525
Eliad Peller53d40d02011-10-10 10:13:02 +02003526 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003527 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003528 }
3529 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003530 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003531 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003532 if (ret < 0)
3533 goto out;
3534
Eliad Peller53d40d02011-10-10 10:13:02 +02003535 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003536 wl1271_debug(DEBUG_AP, "stopped AP");
3537 }
3538 }
3539 }
3540
Eliad Peller0603d892011-10-05 11:55:51 +02003541 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003542 if (ret < 0)
3543 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003544
3545 /* Handle HT information change */
3546 if ((changed & BSS_CHANGED_HT) &&
3547 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003548 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003549 bss_conf->ht_operation_mode);
3550 if (ret < 0) {
3551 wl1271_warning("Set ht information failed %d", ret);
3552 goto out;
3553 }
3554 }
3555
Arik Nemtsove78a2872010-10-16 19:07:21 +02003556out:
3557 return;
3558}
3559
3560/* STA/IBSS mode changes */
3561static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3562 struct ieee80211_vif *vif,
3563 struct ieee80211_bss_conf *bss_conf,
3564 u32 changed)
3565{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003566 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003567 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003568 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003569 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003570 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003571 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003572 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003573 bool sta_exists = false;
3574 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003575
3576 if (is_ibss) {
3577 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3578 changed);
3579 if (ret < 0)
3580 goto out;
3581 }
3582
Eliad Peller227e81e2011-08-14 13:17:26 +03003583 if (changed & BSS_CHANGED_IBSS) {
3584 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003585 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003586 ibss_joined = true;
3587 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003588 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3589 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003590 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003591 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003592 }
3593 }
3594 }
3595
3596 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003597 do_join = true;
3598
3599 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003600 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003601 do_join = true;
3602
Eliad Peller227e81e2011-08-14 13:17:26 +03003603 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003604 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3605 bss_conf->enable_beacon ? "enabled" : "disabled");
3606
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003607 do_join = true;
3608 }
3609
Arik Nemtsove78a2872010-10-16 19:07:21 +02003610 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003611 bool enable = false;
3612 if (bss_conf->cqm_rssi_thold)
3613 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003614 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003615 bss_conf->cqm_rssi_thold,
3616 bss_conf->cqm_rssi_hyst);
3617 if (ret < 0)
3618 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003619 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003620 }
3621
Eliad Pellercdf09492011-10-05 11:55:44 +02003622 if (changed & BSS_CHANGED_BSSID)
3623 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003624 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003625 if (ret < 0)
3626 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003627
Eliad Peller784f6942011-10-05 11:55:39 +02003628 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003629 if (ret < 0)
3630 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003631
Eliad Pellerfa287b82010-12-26 09:27:50 +01003632 /* Need to update the BSSID (for filtering etc) */
3633 do_join = true;
3634 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003635
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003636 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3637 rcu_read_lock();
3638 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3639 if (!sta)
3640 goto sta_not_found;
3641
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003642 /* save the supp_rates of the ap */
3643 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3644 if (sta->ht_cap.ht_supported)
3645 sta_rate_set |=
3646 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003647 sta_ht_cap = sta->ht_cap;
3648 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003649
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003650sta_not_found:
3651 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003652 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003653
Arik Nemtsove78a2872010-10-16 19:07:21 +02003654 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003655 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003656 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003657 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003658 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003659 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003660
Eliad Peller74ec8392011-10-05 11:56:02 +02003661 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003662
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003663 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003664 * use basic rates from AP, and determine lowest rate
3665 * to use with control frames.
3666 */
3667 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003668 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003669 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003670 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003671 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003672 wl1271_tx_min_rate_get(wl,
3673 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003674 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003675 wlvif->rate_set =
3676 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003677 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003678 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003679 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003680 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003681 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003682
3683 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003684 * with wl1271, we don't need to update the
3685 * beacon_int and dtim_period, because the firmware
3686 * updates it by itself when the first beacon is
3687 * received after a join.
3688 */
Eliad Peller6840e372011-10-05 11:55:50 +02003689 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003690 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003691 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003692
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003693 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003694 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003695 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003696 dev_kfree_skb(wlvif->probereq);
3697 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003698 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003699 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003700 ieoffset = offsetof(struct ieee80211_mgmt,
3701 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003702 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003703
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003704 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003705 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003706 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003707 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003708 } else {
3709 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003710 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003711 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3712 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003713 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003714 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3715 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003716 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003717
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003718 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003719 dev_kfree_skb(wlvif->probereq);
3720 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003721
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003722 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003723 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003724
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003725 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003726 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003727 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003728 wl1271_tx_min_rate_get(wl,
3729 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003730 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003731 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003732 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003733
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003734 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003735 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003736
3737 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003738 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003739 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003740 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003741
3742 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003743 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003744 u32 conf_flags = wl->hw->conf.flags;
3745 /*
3746 * we might have to disable roc, if there was
3747 * no IF_OPER_UP notification.
3748 */
3749 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003750 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003751 if (ret < 0)
3752 goto out;
3753 }
3754 /*
3755 * (we also need to disable roc in case of
3756 * roaming on the same channel. until we will
3757 * have a better flow...)
3758 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003759 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3760 ret = wl12xx_croc(wl,
3761 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003762 if (ret < 0)
3763 goto out;
3764 }
3765
Eliad Peller0603d892011-10-05 11:55:51 +02003766 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003767 if (!(conf_flags & IEEE80211_CONF_IDLE))
3768 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003769 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003770 }
3771 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003772
Eliad Pellerd192d262011-05-24 14:33:08 +03003773 if (changed & BSS_CHANGED_IBSS) {
3774 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3775 bss_conf->ibss_joined);
3776
3777 if (bss_conf->ibss_joined) {
3778 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003779 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003780 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003781 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003782 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003783 wl1271_tx_min_rate_get(wl,
3784 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003785
Shahar Levi06b660e2011-09-05 13:54:36 +03003786 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003787 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3788 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003789 if (ret < 0)
3790 goto out;
3791 }
3792 }
3793
Eliad Peller0603d892011-10-05 11:55:51 +02003794 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003795 if (ret < 0)
3796 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003797
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003798 if (changed & BSS_CHANGED_ARP_FILTER) {
3799 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003800 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003801
Eliad Pellerc5312772010-12-09 11:31:27 +02003802 if (bss_conf->arp_addr_cnt == 1 &&
3803 bss_conf->arp_filter_enabled) {
3804 /*
3805 * The template should have been configured only upon
3806 * association. however, it seems that the correct ip
3807 * isn't being set (when sending), so we have to
3808 * reconfigure the template upon every ip change.
3809 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003810 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003811 if (ret < 0) {
3812 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003813 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003814 }
3815
Eliad Peller0603d892011-10-05 11:55:51 +02003816 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003817 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003818 addr);
3819 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003820 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003821
3822 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003823 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003824 }
3825
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003826 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003827 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003828 if (ret < 0) {
3829 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003830 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003831 }
Eliad Peller251c1772011-08-14 13:17:17 +03003832
3833 /* ROC until connected (after EAPOL exchange) */
3834 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003835 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003836 if (ret < 0)
3837 goto out;
3838
Eliad Pellerba8447f2011-10-10 10:13:00 +02003839 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003840 ieee80211_get_operstate(vif));
3841 }
3842 /*
3843 * stop device role if started (we might already be in
3844 * STA role). TODO: make it better.
3845 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003846 if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) {
Eliad Peller679a6732011-10-11 11:55:44 +02003847 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003848 if (ret < 0)
3849 goto out;
3850 }
Eliad Peller05dba352011-08-23 16:37:01 +03003851
3852 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003853 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3854 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003855 enum wl1271_cmd_ps_mode mode;
3856
3857 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003858 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003859 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003860 true);
3861 if (ret < 0)
3862 goto out;
3863 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003864 }
3865
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003866 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003867 if (sta_exists) {
3868 if ((changed & BSS_CHANGED_HT) &&
3869 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003870 ret = wl1271_acx_set_ht_capabilities(wl,
3871 &sta_ht_cap,
3872 true,
Eliad Peller154da672011-10-05 11:55:53 +02003873 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003874 if (ret < 0) {
3875 wl1271_warning("Set ht cap true failed %d",
3876 ret);
3877 goto out;
3878 }
3879 }
3880 /* handle new association without HT and disassociation */
3881 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003882 ret = wl1271_acx_set_ht_capabilities(wl,
3883 &sta_ht_cap,
3884 false,
Eliad Peller154da672011-10-05 11:55:53 +02003885 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003886 if (ret < 0) {
3887 wl1271_warning("Set ht cap false failed %d",
3888 ret);
3889 goto out;
3890 }
3891 }
3892 }
3893
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003894 /* Handle HT information change. Done after join. */
3895 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003896 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003897 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003898 bss_conf->ht_operation_mode);
3899 if (ret < 0) {
3900 wl1271_warning("Set ht information failed %d", ret);
3901 goto out;
3902 }
3903 }
3904
Arik Nemtsove78a2872010-10-16 19:07:21 +02003905out:
3906 return;
3907}
3908
3909static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3910 struct ieee80211_vif *vif,
3911 struct ieee80211_bss_conf *bss_conf,
3912 u32 changed)
3913{
3914 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003915 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3916 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003917 int ret;
3918
3919 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3920 (int)changed);
3921
3922 mutex_lock(&wl->mutex);
3923
3924 if (unlikely(wl->state == WL1271_STATE_OFF))
3925 goto out;
3926
Eliad Peller10c8cd02011-10-10 10:13:06 +02003927 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3928 goto out;
3929
Ido Yariva6208652011-03-01 15:14:41 +02003930 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003931 if (ret < 0)
3932 goto out;
3933
3934 if (is_ap)
3935 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3936 else
3937 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3938
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003939 wl1271_ps_elp_sleep(wl);
3940
3941out:
3942 mutex_unlock(&wl->mutex);
3943}
3944
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003945static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3946 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003947 const struct ieee80211_tx_queue_params *params)
3948{
3949 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003950 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003951 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003952 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003953
3954 mutex_lock(&wl->mutex);
3955
3956 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3957
Kalle Valo4695dc92010-03-18 12:26:38 +02003958 if (params->uapsd)
3959 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3960 else
3961 ps_scheme = CONF_PS_SCHEME_LEGACY;
3962
Arik Nemtsov488fc542010-10-16 20:33:45 +02003963 if (wl->state == WL1271_STATE_OFF) {
3964 /*
3965 * If the state is off, the parameters will be recorded and
3966 * configured on init. This happens in AP-mode.
3967 */
3968 struct conf_tx_ac_category *conf_ac =
3969 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3970 struct conf_tx_tid *conf_tid =
3971 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3972
3973 conf_ac->ac = wl1271_tx_get_queue(queue);
3974 conf_ac->cw_min = (u8)params->cw_min;
3975 conf_ac->cw_max = params->cw_max;
3976 conf_ac->aifsn = params->aifs;
3977 conf_ac->tx_op_limit = params->txop << 5;
3978
3979 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3980 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3981 conf_tid->tsid = wl1271_tx_get_queue(queue);
3982 conf_tid->ps_scheme = ps_scheme;
3983 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3984 conf_tid->apsd_conf[0] = 0;
3985 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003986 goto out;
3987 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003988
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003989 ret = wl1271_ps_elp_wakeup(wl);
3990 if (ret < 0)
3991 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003992
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003993 /*
3994 * the txop is confed in units of 32us by the mac80211,
3995 * we need us
3996 */
Eliad Peller0603d892011-10-05 11:55:51 +02003997 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003998 params->cw_min, params->cw_max,
3999 params->aifs, params->txop << 5);
4000 if (ret < 0)
4001 goto out_sleep;
4002
Eliad Peller0603d892011-10-05 11:55:51 +02004003 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004004 CONF_CHANNEL_TYPE_EDCF,
4005 wl1271_tx_get_queue(queue),
4006 ps_scheme, CONF_ACK_POLICY_LEGACY,
4007 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004008
4009out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004010 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004011
4012out:
4013 mutex_unlock(&wl->mutex);
4014
4015 return ret;
4016}
4017
Eliad Peller37a41b42011-09-21 14:06:11 +03004018static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4019 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004020{
4021
4022 struct wl1271 *wl = hw->priv;
4023 u64 mactime = ULLONG_MAX;
4024 int ret;
4025
4026 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4027
4028 mutex_lock(&wl->mutex);
4029
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004030 if (unlikely(wl->state == WL1271_STATE_OFF))
4031 goto out;
4032
Ido Yariva6208652011-03-01 15:14:41 +02004033 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004034 if (ret < 0)
4035 goto out;
4036
4037 ret = wl1271_acx_tsf_info(wl, &mactime);
4038 if (ret < 0)
4039 goto out_sleep;
4040
4041out_sleep:
4042 wl1271_ps_elp_sleep(wl);
4043
4044out:
4045 mutex_unlock(&wl->mutex);
4046 return mactime;
4047}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004048
John W. Linvilleece550d2010-07-28 16:41:06 -04004049static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4050 struct survey_info *survey)
4051{
4052 struct wl1271 *wl = hw->priv;
4053 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004054
John W. Linvilleece550d2010-07-28 16:41:06 -04004055 if (idx != 0)
4056 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004057
John W. Linvilleece550d2010-07-28 16:41:06 -04004058 survey->channel = conf->channel;
4059 survey->filled = SURVEY_INFO_NOISE_DBM;
4060 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004061
John W. Linvilleece550d2010-07-28 16:41:06 -04004062 return 0;
4063}
4064
Arik Nemtsov409622e2011-02-23 00:22:29 +02004065static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004066 struct wl12xx_vif *wlvif,
4067 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004068{
4069 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004070 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004071
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004072
4073 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004074 wl1271_warning("could not allocate HLID - too much stations");
4075 return -EBUSY;
4076 }
4077
4078 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004079 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4080 if (ret < 0) {
4081 wl1271_warning("could not allocate HLID - too many links");
4082 return -EBUSY;
4083 }
4084
4085 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004086 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004087 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004088 return 0;
4089}
4090
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004091void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004092{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004093 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004094 return;
4095
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004096 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004097 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004098 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004099 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004100 __clear_bit(hlid, &wl->ap_ps_map);
4101 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004102 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004103 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004104}
4105
4106static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4107 struct ieee80211_vif *vif,
4108 struct ieee80211_sta *sta)
4109{
4110 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004111 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004112 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004113 int ret = 0;
4114 u8 hlid;
4115
4116 mutex_lock(&wl->mutex);
4117
4118 if (unlikely(wl->state == WL1271_STATE_OFF))
4119 goto out;
4120
Eliad Peller536129c2011-10-05 11:55:45 +02004121 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004122 goto out;
4123
4124 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4125
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004126 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004127 if (ret < 0)
4128 goto out;
4129
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004130 wl_sta = (struct wl1271_station *)sta->drv_priv;
4131 hlid = wl_sta->hlid;
4132
Ido Yariva6208652011-03-01 15:14:41 +02004133 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004134 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004135 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004136
Eliad Peller1b92f152011-10-10 10:13:09 +02004137 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004138 if (ret < 0)
4139 goto out_sleep;
4140
Eliad Pellerb67476e2011-08-14 13:17:23 +03004141 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4142 if (ret < 0)
4143 goto out_sleep;
4144
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004145 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4146 if (ret < 0)
4147 goto out_sleep;
4148
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004149out_sleep:
4150 wl1271_ps_elp_sleep(wl);
4151
Arik Nemtsov409622e2011-02-23 00:22:29 +02004152out_free_sta:
4153 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004154 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004155
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004156out:
4157 mutex_unlock(&wl->mutex);
4158 return ret;
4159}
4160
4161static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4162 struct ieee80211_vif *vif,
4163 struct ieee80211_sta *sta)
4164{
4165 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004166 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004167 struct wl1271_station *wl_sta;
4168 int ret = 0, id;
4169
4170 mutex_lock(&wl->mutex);
4171
4172 if (unlikely(wl->state == WL1271_STATE_OFF))
4173 goto out;
4174
Eliad Peller536129c2011-10-05 11:55:45 +02004175 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004176 goto out;
4177
4178 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4179
4180 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004181 id = wl_sta->hlid;
4182 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004183 goto out;
4184
Ido Yariva6208652011-03-01 15:14:41 +02004185 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004186 if (ret < 0)
4187 goto out;
4188
Eliad Pellerc690ec82011-08-14 13:17:07 +03004189 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004190 if (ret < 0)
4191 goto out_sleep;
4192
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004193 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004194
4195out_sleep:
4196 wl1271_ps_elp_sleep(wl);
4197
4198out:
4199 mutex_unlock(&wl->mutex);
4200 return ret;
4201}
4202
Luciano Coelho4623ec72011-03-21 19:26:41 +02004203static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4204 struct ieee80211_vif *vif,
4205 enum ieee80211_ampdu_mlme_action action,
4206 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4207 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004208{
4209 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004210 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004211 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004212 u8 hlid, *ba_bitmap;
4213
4214 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4215 tid);
4216
4217 /* sanity check - the fields in FW are only 8bits wide */
4218 if (WARN_ON(tid > 0xFF))
4219 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004220
4221 mutex_lock(&wl->mutex);
4222
4223 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4224 ret = -EAGAIN;
4225 goto out;
4226 }
4227
Eliad Peller536129c2011-10-05 11:55:45 +02004228 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004229 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004230 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004231 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004232 struct wl1271_station *wl_sta;
4233
4234 wl_sta = (struct wl1271_station *)sta->drv_priv;
4235 hlid = wl_sta->hlid;
4236 ba_bitmap = &wl->links[hlid].ba_bitmap;
4237 } else {
4238 ret = -EINVAL;
4239 goto out;
4240 }
4241
Ido Yariva6208652011-03-01 15:14:41 +02004242 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004243 if (ret < 0)
4244 goto out;
4245
Shahar Levi70559a02011-05-22 16:10:22 +03004246 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4247 tid, action);
4248
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004249 switch (action) {
4250 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004251 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004252 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004253 break;
4254 }
4255
4256 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4257 ret = -EBUSY;
4258 wl1271_error("exceeded max RX BA sessions");
4259 break;
4260 }
4261
4262 if (*ba_bitmap & BIT(tid)) {
4263 ret = -EINVAL;
4264 wl1271_error("cannot enable RX BA session on active "
4265 "tid: %d", tid);
4266 break;
4267 }
4268
4269 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4270 hlid);
4271 if (!ret) {
4272 *ba_bitmap |= BIT(tid);
4273 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004274 }
4275 break;
4276
4277 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004278 if (!(*ba_bitmap & BIT(tid))) {
4279 ret = -EINVAL;
4280 wl1271_error("no active RX BA session on tid: %d",
4281 tid);
4282 break;
4283 }
4284
4285 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4286 hlid);
4287 if (!ret) {
4288 *ba_bitmap &= ~BIT(tid);
4289 wl->ba_rx_session_count--;
4290 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004291 break;
4292
4293 /*
4294 * The BA initiator session management in FW independently.
4295 * Falling break here on purpose for all TX APDU commands.
4296 */
4297 case IEEE80211_AMPDU_TX_START:
4298 case IEEE80211_AMPDU_TX_STOP:
4299 case IEEE80211_AMPDU_TX_OPERATIONAL:
4300 ret = -EINVAL;
4301 break;
4302
4303 default:
4304 wl1271_error("Incorrect ampdu action id=%x\n", action);
4305 ret = -EINVAL;
4306 }
4307
4308 wl1271_ps_elp_sleep(wl);
4309
4310out:
4311 mutex_unlock(&wl->mutex);
4312
4313 return ret;
4314}
4315
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004316static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4317 struct ieee80211_vif *vif,
4318 const struct cfg80211_bitrate_mask *mask)
4319{
Eliad Peller83587502011-10-10 10:12:53 +02004320 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004321 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004322 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004323
4324 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4325 mask->control[NL80211_BAND_2GHZ].legacy,
4326 mask->control[NL80211_BAND_5GHZ].legacy);
4327
4328 mutex_lock(&wl->mutex);
4329
4330 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004331 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004332 wl1271_tx_enabled_rates_get(wl,
4333 mask->control[i].legacy,
4334 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004335
4336 if (unlikely(wl->state == WL1271_STATE_OFF))
4337 goto out;
4338
4339 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4340 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4341
4342 ret = wl1271_ps_elp_wakeup(wl);
4343 if (ret < 0)
4344 goto out;
4345
4346 wl1271_set_band_rate(wl, wlvif);
4347 wlvif->basic_rate =
4348 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4349 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4350
4351 wl1271_ps_elp_sleep(wl);
4352 }
4353out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004354 mutex_unlock(&wl->mutex);
4355
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004356 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004357}
4358
Shahar Levi6d158ff2011-09-08 13:01:33 +03004359static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4360 struct ieee80211_channel_switch *ch_switch)
4361{
4362 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004363 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004364 int ret;
4365
4366 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4367
4368 mutex_lock(&wl->mutex);
4369
4370 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004371 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4372 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4373 ieee80211_chswitch_done(vif, false);
4374 }
4375 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004376 }
4377
4378 ret = wl1271_ps_elp_wakeup(wl);
4379 if (ret < 0)
4380 goto out;
4381
Eliad Peller52630c52011-10-10 10:13:08 +02004382 /* TODO: change mac80211 to pass vif as param */
4383 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4384 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004385
Eliad Peller52630c52011-10-10 10:13:08 +02004386 if (!ret)
4387 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4388 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004389
4390 wl1271_ps_elp_sleep(wl);
4391
4392out:
4393 mutex_unlock(&wl->mutex);
4394}
4395
Arik Nemtsov33437892011-04-26 23:35:39 +03004396static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4397{
4398 struct wl1271 *wl = hw->priv;
4399 bool ret = false;
4400
4401 mutex_lock(&wl->mutex);
4402
4403 if (unlikely(wl->state == WL1271_STATE_OFF))
4404 goto out;
4405
4406 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004407 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004408out:
4409 mutex_unlock(&wl->mutex);
4410
4411 return ret;
4412}
4413
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004414/* can't be const, mac80211 writes to this */
4415static struct ieee80211_rate wl1271_rates[] = {
4416 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004417 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4418 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004419 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004420 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4421 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004422 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4423 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004424 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4425 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004426 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4427 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004428 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4429 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004430 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4431 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004432 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4433 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004434 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004435 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4436 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004437 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004438 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4439 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004440 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004441 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4442 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004443 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004444 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4445 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004446 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004447 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4448 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004449 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004450 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4451 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004452 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004453 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4454 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004455};
4456
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004457/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004458static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004459 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004460 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004461 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4462 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4463 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004464 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004465 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4466 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4467 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004468 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004469 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4470 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4471 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004472 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004473};
4474
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004475/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004476static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004477 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004478 7, /* CONF_HW_RXTX_RATE_MCS7 */
4479 6, /* CONF_HW_RXTX_RATE_MCS6 */
4480 5, /* CONF_HW_RXTX_RATE_MCS5 */
4481 4, /* CONF_HW_RXTX_RATE_MCS4 */
4482 3, /* CONF_HW_RXTX_RATE_MCS3 */
4483 2, /* CONF_HW_RXTX_RATE_MCS2 */
4484 1, /* CONF_HW_RXTX_RATE_MCS1 */
4485 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004486
4487 11, /* CONF_HW_RXTX_RATE_54 */
4488 10, /* CONF_HW_RXTX_RATE_48 */
4489 9, /* CONF_HW_RXTX_RATE_36 */
4490 8, /* CONF_HW_RXTX_RATE_24 */
4491
4492 /* TI-specific rate */
4493 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4494
4495 7, /* CONF_HW_RXTX_RATE_18 */
4496 6, /* CONF_HW_RXTX_RATE_12 */
4497 3, /* CONF_HW_RXTX_RATE_11 */
4498 5, /* CONF_HW_RXTX_RATE_9 */
4499 4, /* CONF_HW_RXTX_RATE_6 */
4500 2, /* CONF_HW_RXTX_RATE_5_5 */
4501 1, /* CONF_HW_RXTX_RATE_2 */
4502 0 /* CONF_HW_RXTX_RATE_1 */
4503};
4504
Shahar Levie8b03a22010-10-13 16:09:39 +02004505/* 11n STA capabilities */
4506#define HW_RX_HIGHEST_RATE 72
4507
Shahar Levi00d20102010-11-08 11:20:10 +00004508#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004509 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4510 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004511 .ht_supported = true, \
4512 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4513 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4514 .mcs = { \
4515 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4516 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4517 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4518 }, \
4519}
4520
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004521/* can't be const, mac80211 writes to this */
4522static struct ieee80211_supported_band wl1271_band_2ghz = {
4523 .channels = wl1271_channels,
4524 .n_channels = ARRAY_SIZE(wl1271_channels),
4525 .bitrates = wl1271_rates,
4526 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004527 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004528};
4529
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004530/* 5 GHz data rates for WL1273 */
4531static struct ieee80211_rate wl1271_rates_5ghz[] = {
4532 { .bitrate = 60,
4533 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4534 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4535 { .bitrate = 90,
4536 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4537 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4538 { .bitrate = 120,
4539 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4540 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4541 { .bitrate = 180,
4542 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4543 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4544 { .bitrate = 240,
4545 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4546 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4547 { .bitrate = 360,
4548 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4549 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4550 { .bitrate = 480,
4551 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4552 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4553 { .bitrate = 540,
4554 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4555 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4556};
4557
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004558/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004559static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004560 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4561 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4562 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4563 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4564 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4565 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4566 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4567 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4568 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4569 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4570 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4571 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4572 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4573 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4574 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4575 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4576 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4577 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4578 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4579 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4580 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4581 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4582 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4583 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4584 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4585 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4586 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4587 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4588 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4589 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4590 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4591 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4592 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4593 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004594};
4595
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004596/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004597static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004598 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004599 7, /* CONF_HW_RXTX_RATE_MCS7 */
4600 6, /* CONF_HW_RXTX_RATE_MCS6 */
4601 5, /* CONF_HW_RXTX_RATE_MCS5 */
4602 4, /* CONF_HW_RXTX_RATE_MCS4 */
4603 3, /* CONF_HW_RXTX_RATE_MCS3 */
4604 2, /* CONF_HW_RXTX_RATE_MCS2 */
4605 1, /* CONF_HW_RXTX_RATE_MCS1 */
4606 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004607
4608 7, /* CONF_HW_RXTX_RATE_54 */
4609 6, /* CONF_HW_RXTX_RATE_48 */
4610 5, /* CONF_HW_RXTX_RATE_36 */
4611 4, /* CONF_HW_RXTX_RATE_24 */
4612
4613 /* TI-specific rate */
4614 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4615
4616 3, /* CONF_HW_RXTX_RATE_18 */
4617 2, /* CONF_HW_RXTX_RATE_12 */
4618 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4619 1, /* CONF_HW_RXTX_RATE_9 */
4620 0, /* CONF_HW_RXTX_RATE_6 */
4621 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4622 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4623 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4624};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004625
4626static struct ieee80211_supported_band wl1271_band_5ghz = {
4627 .channels = wl1271_channels_5ghz,
4628 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4629 .bitrates = wl1271_rates_5ghz,
4630 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004631 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004632};
4633
Tobias Klausera0ea9492010-05-20 10:38:11 +02004634static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004635 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4636 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4637};
4638
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004639static const struct ieee80211_ops wl1271_ops = {
4640 .start = wl1271_op_start,
4641 .stop = wl1271_op_stop,
4642 .add_interface = wl1271_op_add_interface,
4643 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004644#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004645 .suspend = wl1271_op_suspend,
4646 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004647#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004648 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004649 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004650 .configure_filter = wl1271_op_configure_filter,
4651 .tx = wl1271_op_tx,
4652 .set_key = wl1271_op_set_key,
4653 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004654 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004655 .sched_scan_start = wl1271_op_sched_scan_start,
4656 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004657 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004658 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004659 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004660 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004661 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004662 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004663 .sta_add = wl1271_op_sta_add,
4664 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004665 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004666 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004667 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004668 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004669 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004670};
4671
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004672
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004673u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004674{
4675 u8 idx;
4676
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004677 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004678
4679 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4680 wl1271_error("Illegal RX rate from HW: %d", rate);
4681 return 0;
4682 }
4683
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004684 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004685 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4686 wl1271_error("Unsupported RX rate from HW: %d", rate);
4687 return 0;
4688 }
4689
4690 return idx;
4691}
4692
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004693static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4694 struct device_attribute *attr,
4695 char *buf)
4696{
4697 struct wl1271 *wl = dev_get_drvdata(dev);
4698 ssize_t len;
4699
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004700 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004701
4702 mutex_lock(&wl->mutex);
4703 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4704 wl->sg_enabled);
4705 mutex_unlock(&wl->mutex);
4706
4707 return len;
4708
4709}
4710
4711static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4712 struct device_attribute *attr,
4713 const char *buf, size_t count)
4714{
4715 struct wl1271 *wl = dev_get_drvdata(dev);
4716 unsigned long res;
4717 int ret;
4718
Luciano Coelho6277ed62011-04-01 17:49:54 +03004719 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004720 if (ret < 0) {
4721 wl1271_warning("incorrect value written to bt_coex_mode");
4722 return count;
4723 }
4724
4725 mutex_lock(&wl->mutex);
4726
4727 res = !!res;
4728
4729 if (res == wl->sg_enabled)
4730 goto out;
4731
4732 wl->sg_enabled = res;
4733
4734 if (wl->state == WL1271_STATE_OFF)
4735 goto out;
4736
Ido Yariva6208652011-03-01 15:14:41 +02004737 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004738 if (ret < 0)
4739 goto out;
4740
4741 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4742 wl1271_ps_elp_sleep(wl);
4743
4744 out:
4745 mutex_unlock(&wl->mutex);
4746 return count;
4747}
4748
4749static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4750 wl1271_sysfs_show_bt_coex_state,
4751 wl1271_sysfs_store_bt_coex_state);
4752
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004753static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4754 struct device_attribute *attr,
4755 char *buf)
4756{
4757 struct wl1271 *wl = dev_get_drvdata(dev);
4758 ssize_t len;
4759
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004760 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004761
4762 mutex_lock(&wl->mutex);
4763 if (wl->hw_pg_ver >= 0)
4764 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4765 else
4766 len = snprintf(buf, len, "n/a\n");
4767 mutex_unlock(&wl->mutex);
4768
4769 return len;
4770}
4771
Gery Kahn6f07b722011-07-18 14:21:49 +03004772static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004773 wl1271_sysfs_show_hw_pg_ver, NULL);
4774
Ido Yariv95dac04f2011-06-06 14:57:06 +03004775static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4776 struct bin_attribute *bin_attr,
4777 char *buffer, loff_t pos, size_t count)
4778{
4779 struct device *dev = container_of(kobj, struct device, kobj);
4780 struct wl1271 *wl = dev_get_drvdata(dev);
4781 ssize_t len;
4782 int ret;
4783
4784 ret = mutex_lock_interruptible(&wl->mutex);
4785 if (ret < 0)
4786 return -ERESTARTSYS;
4787
4788 /* Let only one thread read the log at a time, blocking others */
4789 while (wl->fwlog_size == 0) {
4790 DEFINE_WAIT(wait);
4791
4792 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4793 &wait,
4794 TASK_INTERRUPTIBLE);
4795
4796 if (wl->fwlog_size != 0) {
4797 finish_wait(&wl->fwlog_waitq, &wait);
4798 break;
4799 }
4800
4801 mutex_unlock(&wl->mutex);
4802
4803 schedule();
4804 finish_wait(&wl->fwlog_waitq, &wait);
4805
4806 if (signal_pending(current))
4807 return -ERESTARTSYS;
4808
4809 ret = mutex_lock_interruptible(&wl->mutex);
4810 if (ret < 0)
4811 return -ERESTARTSYS;
4812 }
4813
4814 /* Check if the fwlog is still valid */
4815 if (wl->fwlog_size < 0) {
4816 mutex_unlock(&wl->mutex);
4817 return 0;
4818 }
4819
4820 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4821 len = min(count, (size_t)wl->fwlog_size);
4822 wl->fwlog_size -= len;
4823 memcpy(buffer, wl->fwlog, len);
4824
4825 /* Make room for new messages */
4826 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4827
4828 mutex_unlock(&wl->mutex);
4829
4830 return len;
4831}
4832
4833static struct bin_attribute fwlog_attr = {
4834 .attr = {.name = "fwlog", .mode = S_IRUSR},
4835 .read = wl1271_sysfs_read_fwlog,
4836};
4837
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004838static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004839{
4840 int ret;
4841
4842 if (wl->mac80211_registered)
4843 return 0;
4844
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004845 ret = wl1271_fetch_nvs(wl);
4846 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004847 /* NOTE: The wl->nvs->nvs element must be first, in
4848 * order to simplify the casting, we assume it is at
4849 * the beginning of the wl->nvs structure.
4850 */
4851 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004852
4853 wl->mac_addr[0] = nvs_ptr[11];
4854 wl->mac_addr[1] = nvs_ptr[10];
4855 wl->mac_addr[2] = nvs_ptr[6];
4856 wl->mac_addr[3] = nvs_ptr[5];
4857 wl->mac_addr[4] = nvs_ptr[4];
4858 wl->mac_addr[5] = nvs_ptr[3];
4859 }
4860
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004861 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4862
4863 ret = ieee80211_register_hw(wl->hw);
4864 if (ret < 0) {
4865 wl1271_error("unable to register mac80211 hw: %d", ret);
4866 return ret;
4867 }
4868
4869 wl->mac80211_registered = true;
4870
Eliad Pellerd60080a2010-11-24 12:53:16 +02004871 wl1271_debugfs_init(wl);
4872
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004873 register_netdevice_notifier(&wl1271_dev_notifier);
4874
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004875 wl1271_notice("loaded");
4876
4877 return 0;
4878}
4879
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004880static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004881{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004882 if (wl->state == WL1271_STATE_PLT)
4883 __wl1271_plt_stop(wl);
4884
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004885 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004886 ieee80211_unregister_hw(wl->hw);
4887 wl->mac80211_registered = false;
4888
4889}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004890
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004891static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004892{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004893 static const u32 cipher_suites[] = {
4894 WLAN_CIPHER_SUITE_WEP40,
4895 WLAN_CIPHER_SUITE_WEP104,
4896 WLAN_CIPHER_SUITE_TKIP,
4897 WLAN_CIPHER_SUITE_CCMP,
4898 WL1271_CIPHER_SUITE_GEM,
4899 };
4900
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004901 /* The tx descriptor buffer and the TKIP space. */
4902 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4903 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004904
4905 /* unit us */
4906 /* FIXME: find a proper value */
4907 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004908 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004909
4910 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004911 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004912 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004913 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004914 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004915 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004916 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004917 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004918 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004919 IEEE80211_HW_AP_LINK_PS |
4920 IEEE80211_HW_AMPDU_AGGREGATION |
4921 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004922
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004923 wl->hw->wiphy->cipher_suites = cipher_suites;
4924 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4925
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004926 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004927 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4928 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004929 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004930 wl->hw->wiphy->max_sched_scan_ssids = 16;
4931 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004932 /*
4933 * Maximum length of elements in scanning probe request templates
4934 * should be the maximum length possible for a template, without
4935 * the IEEE80211 header of the template
4936 */
Eliad Peller154037d2011-08-14 13:17:12 +03004937 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004938 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004939
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004940 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4941 sizeof(struct ieee80211_header);
4942
Eliad Peller1ec23f72011-08-25 14:26:54 +03004943 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4944
Luciano Coelho4a31c112011-03-21 23:16:14 +02004945 /* make sure all our channels fit in the scanned_ch bitmask */
4946 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4947 ARRAY_SIZE(wl1271_channels_5ghz) >
4948 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004949 /*
4950 * We keep local copies of the band structs because we need to
4951 * modify them on a per-device basis.
4952 */
4953 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4954 sizeof(wl1271_band_2ghz));
4955 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4956 sizeof(wl1271_band_5ghz));
4957
4958 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4959 &wl->bands[IEEE80211_BAND_2GHZ];
4960 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4961 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004962
Kalle Valo12bd8942010-03-18 12:26:33 +02004963 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004964 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004965
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004966 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4967
Felipe Balbia390e852011-10-06 10:07:44 +03004968 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004969
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004970 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004971 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004972
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004973 wl->hw->max_rx_aggregation_subframes = 8;
4974
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004975 return 0;
4976}
4977
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004978#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004979
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004980static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004981{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004982 struct ieee80211_hw *hw;
4983 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004984 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004985 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004986
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004987 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004988
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004989 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4990 if (!hw) {
4991 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004992 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004993 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004994 }
4995
4996 wl = hw->priv;
4997 memset(wl, 0, sizeof(*wl));
4998
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004999 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005000 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005001
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005002 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005003
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005004 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005005 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005006 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5007
Ido Yariva6208652011-03-01 15:14:41 +02005008 skb_queue_head_init(&wl->deferred_rx_queue);
5009 skb_queue_head_init(&wl->deferred_tx_queue);
5010
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005011 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005012 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005013 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5014 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5015 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005016
Eliad Peller92ef8962011-06-07 12:50:46 +03005017 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5018 if (!wl->freezable_wq) {
5019 ret = -ENOMEM;
5020 goto err_hw;
5021 }
5022
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005023 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005024 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005025 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005026 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005027 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005028 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005029 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005030 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005031 wl->ap_ps_map = 0;
5032 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005033 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005034 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005035 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005036 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005037 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005038 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005039 wl->fwlog_size = 0;
5040 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005041
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005042 /* The system link is always allocated */
5043 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5044
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005045 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005046 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005047 wl->tx_frames[i] = NULL;
5048
5049 spin_lock_init(&wl->wl_lock);
5050
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005051 wl->state = WL1271_STATE_OFF;
5052 mutex_init(&wl->mutex);
5053
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005054 /* Apply default driver configuration. */
5055 wl1271_conf_init(wl);
5056
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005057 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5058 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5059 if (!wl->aggr_buf) {
5060 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005061 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005062 }
5063
Ido Yariv990f5de2011-03-31 10:06:59 +02005064 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5065 if (!wl->dummy_packet) {
5066 ret = -ENOMEM;
5067 goto err_aggr;
5068 }
5069
Ido Yariv95dac04f2011-06-06 14:57:06 +03005070 /* Allocate one page for the FW log */
5071 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5072 if (!wl->fwlog) {
5073 ret = -ENOMEM;
5074 goto err_dummy_packet;
5075 }
5076
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005077 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005078
Ido Yariv990f5de2011-03-31 10:06:59 +02005079err_dummy_packet:
5080 dev_kfree_skb(wl->dummy_packet);
5081
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005082err_aggr:
5083 free_pages((unsigned long)wl->aggr_buf, order);
5084
Eliad Peller92ef8962011-06-07 12:50:46 +03005085err_wq:
5086 destroy_workqueue(wl->freezable_wq);
5087
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005088err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005089 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005090 ieee80211_free_hw(hw);
5091
5092err_hw_alloc:
5093
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005094 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005095}
5096
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005097static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005098{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005099 /* Unblock any fwlog readers */
5100 mutex_lock(&wl->mutex);
5101 wl->fwlog_size = -1;
5102 wake_up_interruptible_all(&wl->fwlog_waitq);
5103 mutex_unlock(&wl->mutex);
5104
Felipe Balbif79f8902011-10-06 13:05:25 +03005105 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005106
Felipe Balbif79f8902011-10-06 13:05:25 +03005107 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005108
Felipe Balbif79f8902011-10-06 13:05:25 +03005109 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005110 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005111 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005112 free_pages((unsigned long)wl->aggr_buf,
5113 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005114
5115 wl1271_debugfs_exit(wl);
5116
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005117 vfree(wl->fw);
5118 wl->fw = NULL;
5119 kfree(wl->nvs);
5120 wl->nvs = NULL;
5121
5122 kfree(wl->fw_status);
5123 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005124 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005125
5126 ieee80211_free_hw(wl->hw);
5127
5128 return 0;
5129}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005130
Felipe Balbia390e852011-10-06 10:07:44 +03005131static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5132{
5133 struct wl1271 *wl = cookie;
5134 unsigned long flags;
5135
5136 wl1271_debug(DEBUG_IRQ, "IRQ");
5137
5138 /* complete the ELP completion */
5139 spin_lock_irqsave(&wl->wl_lock, flags);
5140 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5141 if (wl->elp_compl) {
5142 complete(wl->elp_compl);
5143 wl->elp_compl = NULL;
5144 }
5145
5146 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5147 /* don't enqueue a work right now. mark it as pending */
5148 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5149 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5150 disable_irq_nosync(wl->irq);
5151 pm_wakeup_event(wl->dev, 0);
5152 spin_unlock_irqrestore(&wl->wl_lock, flags);
5153 return IRQ_HANDLED;
5154 }
5155 spin_unlock_irqrestore(&wl->wl_lock, flags);
5156
5157 return IRQ_WAKE_THREAD;
5158}
5159
Felipe Balbice2a2172011-10-05 14:12:55 +03005160static int __devinit wl12xx_probe(struct platform_device *pdev)
5161{
Felipe Balbia390e852011-10-06 10:07:44 +03005162 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5163 struct ieee80211_hw *hw;
5164 struct wl1271 *wl;
5165 unsigned long irqflags;
5166 int ret = -ENODEV;
5167
5168 hw = wl1271_alloc_hw();
5169 if (IS_ERR(hw)) {
5170 wl1271_error("can't allocate hw");
5171 ret = PTR_ERR(hw);
5172 goto out;
5173 }
5174
5175 wl = hw->priv;
5176 wl->irq = platform_get_irq(pdev, 0);
5177 wl->ref_clock = pdata->board_ref_clock;
5178 wl->tcxo_clock = pdata->board_tcxo_clock;
5179 wl->platform_quirks = pdata->platform_quirks;
5180 wl->set_power = pdata->set_power;
5181 wl->dev = &pdev->dev;
5182 wl->if_ops = pdata->ops;
5183
5184 platform_set_drvdata(pdev, wl);
5185
5186 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5187 irqflags = IRQF_TRIGGER_RISING;
5188 else
5189 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5190
5191 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5192 irqflags,
5193 pdev->name, wl);
5194 if (ret < 0) {
5195 wl1271_error("request_irq() failed: %d", ret);
5196 goto out_free_hw;
5197 }
5198
5199 ret = enable_irq_wake(wl->irq);
5200 if (!ret) {
5201 wl->irq_wake_enabled = true;
5202 device_init_wakeup(wl->dev, 1);
5203 if (pdata->pwr_in_suspend)
5204 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5205
5206 }
5207 disable_irq(wl->irq);
5208
5209 ret = wl1271_init_ieee80211(wl);
5210 if (ret)
5211 goto out_irq;
5212
5213 ret = wl1271_register_hw(wl);
5214 if (ret)
5215 goto out_irq;
5216
Felipe Balbif79f8902011-10-06 13:05:25 +03005217 /* Create sysfs file to control bt coex state */
5218 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5219 if (ret < 0) {
5220 wl1271_error("failed to create sysfs file bt_coex_state");
5221 goto out_irq;
5222 }
5223
5224 /* Create sysfs file to get HW PG version */
5225 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5226 if (ret < 0) {
5227 wl1271_error("failed to create sysfs file hw_pg_ver");
5228 goto out_bt_coex_state;
5229 }
5230
5231 /* Create sysfs file for the FW log */
5232 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5233 if (ret < 0) {
5234 wl1271_error("failed to create sysfs file fwlog");
5235 goto out_hw_pg_ver;
5236 }
5237
Felipe Balbice2a2172011-10-05 14:12:55 +03005238 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005239
Felipe Balbif79f8902011-10-06 13:05:25 +03005240out_hw_pg_ver:
5241 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5242
5243out_bt_coex_state:
5244 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5245
Felipe Balbia390e852011-10-06 10:07:44 +03005246out_irq:
5247 free_irq(wl->irq, wl);
5248
5249out_free_hw:
5250 wl1271_free_hw(wl);
5251
5252out:
5253 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005254}
5255
5256static int __devexit wl12xx_remove(struct platform_device *pdev)
5257{
Felipe Balbia390e852011-10-06 10:07:44 +03005258 struct wl1271 *wl = platform_get_drvdata(pdev);
5259
5260 if (wl->irq_wake_enabled) {
5261 device_init_wakeup(wl->dev, 0);
5262 disable_irq_wake(wl->irq);
5263 }
5264 wl1271_unregister_hw(wl);
5265 free_irq(wl->irq, wl);
5266 wl1271_free_hw(wl);
5267
Felipe Balbice2a2172011-10-05 14:12:55 +03005268 return 0;
5269}
5270
5271static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005272 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005273 { } /* Terminating Entry */
5274};
5275MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5276
5277static struct platform_driver wl12xx_driver = {
5278 .probe = wl12xx_probe,
5279 .remove = __devexit_p(wl12xx_remove),
5280 .id_table = wl12xx_id_table,
5281 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005282 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005283 .owner = THIS_MODULE,
5284 }
5285};
5286
5287static int __init wl12xx_init(void)
5288{
5289 return platform_driver_register(&wl12xx_driver);
5290}
5291module_init(wl12xx_init);
5292
5293static void __exit wl12xx_exit(void)
5294{
5295 platform_driver_unregister(&wl12xx_driver);
5296}
5297module_exit(wl12xx_exit);
5298
Guy Eilam491bbd62011-01-12 10:33:29 +01005299u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005300EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005301module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005302MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5303
Ido Yariv95dac04f2011-06-06 14:57:06 +03005304module_param_named(fwlog, fwlog_param, charp, 0);
5305MODULE_PARM_DESC(keymap,
5306 "FW logger options: continuous, ondemand, dbgpins or disable");
5307
Eliad Peller2a5bff02011-08-25 18:10:59 +03005308module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5309MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5310
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005311MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005312MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005313MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");