blob: 44070e66cfeda97fb5af383715fac6f987973182 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Felipe Balbia390e852011-10-06 10:07:44 +030035#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "wl12xx.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030038#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030039#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000040#include "reg.h"
41#include "io.h"
42#include "event.h"
43#include "tx.h"
44#include "rx.h"
45#include "ps.h"
46#include "init.h"
47#include "debugfs.h"
48#include "cmd.h"
49#include "boot.h"
50#include "testmode.h"
51#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030052
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020053#define WL1271_BOOT_RETRIES 3
54
Juuso Oikarinen8a080482009-10-13 12:47:44 +030055static struct conf_drv_settings default_conf = {
56 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030057 .params = {
58 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
61 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
62 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
64 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
65 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
66 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
68 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
69 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
70 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
71 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
73 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
74 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
75 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
76 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
77 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
78 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
79 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
82 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
83 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
84 /* active scan params */
85 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
86 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
87 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
88 /* passive scan params */
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
91 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
92 /* passive scan in dual antenna params */
93 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
94 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
95 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
96 /* general params */
97 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
98 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
99 [CONF_SG_BEACON_MISS_PERCENT] = 60,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_RXT] = 1200,
102 [CONF_SG_TXT] = 1000,
103 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
104 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
105 [CONF_SG_HV3_MAX_SERVED] = 6,
106 [CONF_SG_PS_POLL_TIMEOUT] = 10,
107 [CONF_SG_UPSD_TIMEOUT] = 10,
108 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
109 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
110 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
111 /* AP params */
112 [CONF_AP_BEACON_MISS_TX] = 3,
113 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
114 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
115 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
116 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
117 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300118 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200119 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300120 },
121 .rx = {
122 .rx_msdu_life_time = 512000,
123 .packet_detection_threshold = 0,
124 .ps_poll_timeout = 15,
125 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300126 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200127 .rx_cca_threshold = 0,
128 .irq_blk_threshold = 0xFFFF,
129 .irq_pkt_threshold = 0,
130 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300131 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
132 },
133 .tx = {
134 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200135 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300136 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300137 .short_retry_limit = 10,
138 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200139 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300140 },
141 .ac_conf_count = 4,
142 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200143 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300144 .ac = CONF_TX_AC_BE,
145 .cw_min = 15,
146 .cw_max = 63,
147 .aifsn = 3,
148 .tx_op_limit = 0,
149 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200150 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300151 .ac = CONF_TX_AC_BK,
152 .cw_min = 15,
153 .cw_max = 63,
154 .aifsn = 7,
155 .tx_op_limit = 0,
156 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200157 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300158 .ac = CONF_TX_AC_VI,
159 .cw_min = 15,
160 .cw_max = 63,
161 .aifsn = CONF_TX_AIFS_PIFS,
162 .tx_op_limit = 3008,
163 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200164 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300165 .ac = CONF_TX_AC_VO,
166 .cw_min = 15,
167 .cw_max = 63,
168 .aifsn = CONF_TX_AIFS_PIFS,
169 .tx_op_limit = 1504,
170 },
171 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300172 .max_tx_retries = 100,
173 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300175 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200176 [CONF_TX_AC_BE] = {
177 .queue_id = CONF_TX_AC_BE,
178 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300179 .tsid = CONF_TX_AC_BE,
180 .ps_scheme = CONF_PS_SCHEME_LEGACY,
181 .ack_policy = CONF_ACK_POLICY_LEGACY,
182 .apsd_conf = {0, 0},
183 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200184 [CONF_TX_AC_BK] = {
185 .queue_id = CONF_TX_AC_BK,
186 .channel_type = CONF_CHANNEL_TYPE_EDCF,
187 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300188 .ps_scheme = CONF_PS_SCHEME_LEGACY,
189 .ack_policy = CONF_ACK_POLICY_LEGACY,
190 .apsd_conf = {0, 0},
191 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200192 [CONF_TX_AC_VI] = {
193 .queue_id = CONF_TX_AC_VI,
194 .channel_type = CONF_CHANNEL_TYPE_EDCF,
195 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .ps_scheme = CONF_PS_SCHEME_LEGACY,
197 .ack_policy = CONF_ACK_POLICY_LEGACY,
198 .apsd_conf = {0, 0},
199 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200200 [CONF_TX_AC_VO] = {
201 .queue_id = CONF_TX_AC_VO,
202 .channel_type = CONF_CHANNEL_TYPE_EDCF,
203 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300204 .ps_scheme = CONF_PS_SCHEME_LEGACY,
205 .ack_policy = CONF_ACK_POLICY_LEGACY,
206 .apsd_conf = {0, 0},
207 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300208 },
209 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200210 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300211 .tx_compl_threshold = 4,
212 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
213 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200214 .tmpl_short_retry_limit = 10,
215 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300216 },
217 .conn = {
218 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300219 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300221 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300222 .bcn_filt_ie = {
223 [0] = {
224 .ie = WLAN_EID_CHANNEL_SWITCH,
225 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300226 },
227 [1] = {
228 .ie = WLAN_EID_HT_INFORMATION,
229 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
230 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200232 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 .bss_lose_timeout = 100,
234 .beacon_rx_timeout = 10000,
235 .broadcast_timeout = 20000,
236 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300237 .ps_poll_threshold = 10,
238 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300239 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e02011-03-14 18:53:10 +0200240 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300241 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300242 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200243 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300244 .keep_alive_interval = 55000,
245 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300246 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200247 .itrim = {
248 .enable = false,
249 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200250 },
251 .pm_config = {
252 .host_clk_settling_time = 5000,
253 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 },
255 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300256 .trigger_pacing = 1,
257 .avg_weight_rssi_beacon = 20,
258 .avg_weight_rssi_data = 10,
259 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100260 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200261 },
262 .scan = {
263 .min_dwell_time_active = 7500,
264 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100265 .min_dwell_time_passive = 100000,
266 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200267 .num_probe_reqs = 2,
268 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300269 .sched_scan = {
270 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300271 .min_dwell_time_active = 30,
272 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300274 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300275 .num_probe_reqs = 2,
276 .rssi_threshold = -90,
277 .snr_threshold = 0,
278 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200279 .rf = {
280 .tx_per_channel_power_compensation_2 = {
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 },
283 .tx_per_channel_power_compensation_5 = {
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 },
288 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300290 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100291 .tx_ba_win_size = 64,
292 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300293 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100294 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200295 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200296 .num_stations = 1,
297 .ssid_profiles = 1,
298 .rx_block_num = 70,
299 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300300 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200301 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200302 .min_req_rx_blocks = 22,
303 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200304 },
305 .mem_wl128x = {
306 .num_stations = 1,
307 .ssid_profiles = 1,
308 .rx_block_num = 40,
309 .tx_min_block_num = 40,
310 .dynamic_memory = 1,
311 .min_req_tx_blocks = 45,
312 .min_req_rx_blocks = 22,
313 .tx_min = 27,
314 },
Shahar Leviff868432011-04-11 15:41:46 +0300315 .fm_coex = {
316 .enable = true,
317 .swallow_period = 5,
318 .n_divider_fref_set_1 = 0xff, /* default */
319 .n_divider_fref_set_2 = 12,
320 .m_divider_fref_set_1 = 148,
321 .m_divider_fref_set_2 = 0xffff, /* default */
322 .coex_pll_stabilization_time = 0xffffffff, /* default */
323 .ldo_stabilization_time = 0xffff, /* default */
324 .fm_disturbed_band_margin = 0xff, /* default */
325 .swallow_clk_diff = 0xff, /* default */
326 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300327 .rx_streaming = {
328 .duration = 150,
329 .queues = 0x1,
330 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300331 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300332 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300333 .fwlog = {
334 .mode = WL12XX_FWLOG_ON_DEMAND,
335 .mem_blocks = 2,
336 .severity = 0,
337 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
338 .output = WL12XX_FWLOG_OUTPUT_HOST,
339 .threshold = 0,
340 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300341 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300342 .rate = {
343 .rate_retry_score = 32000,
344 .per_add = 8192,
345 .per_th1 = 2048,
346 .per_th2 = 4096,
347 .max_per = 8100,
348 .inverse_curiosity_factor = 5,
349 .tx_fail_low_th = 4,
350 .tx_fail_high_th = 10,
351 .per_alpha_shift = 4,
352 .per_add_shift = 13,
353 .per_beta1_shift = 10,
354 .per_beta2_shift = 8,
355 .rate_check_up = 2,
356 .rate_check_down = 12,
357 .rate_retry_policy = {
358 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00,
361 },
362 },
Eliad Peller94877752011-08-28 15:11:56 +0300363 .hangover = {
364 .recover_time = 0,
365 .hangover_period = 20,
366 .dynamic_mode = 1,
367 .early_termination_mode = 1,
368 .max_period = 20,
369 .min_period = 1,
370 .increase_delta = 1,
371 .decrease_delta = 2,
372 .quiet_time = 4,
373 .increase_time = 1,
374 .window_size = 16,
375 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300376};
377
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300379static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300380
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300381static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad 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 Oikarinen01ac17ec2009-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;
1862 wl->vif = NULL;
1863 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1864 wl->ap_fw_ps_map = 0;
1865 wl->ap_ps_map = 0;
1866 wl->sched_scanning = false;
1867 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1868 memset(wl->links_map, 0, sizeof(wl->links_map));
1869 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1870 wl->active_sta_count = 0;
1871
1872 /* The system link is always allocated */
1873 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1874
1875 /*
1876 * this is performed after the cancel_work calls and the associated
1877 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1878 * get executed before all these vars have been reset.
1879 */
1880 wl->flags = 0;
1881
1882 wl->tx_blocks_freed = 0;
1883
1884 for (i = 0; i < NUM_TX_QUEUES; i++) {
1885 wl->tx_pkts_freed[i] = 0;
1886 wl->tx_allocated_pkts[i] = 0;
1887 }
1888
1889 wl1271_debugfs_reset(wl);
1890
1891 kfree(wl->fw_status);
1892 wl->fw_status = NULL;
1893 kfree(wl->tx_res_if);
1894 wl->tx_res_if = NULL;
1895 kfree(wl->target_mem_map);
1896 wl->target_mem_map = NULL;
1897
1898 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001899}
1900
Eliad Pellere5a359f2011-10-10 10:13:15 +02001901static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1902{
1903 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1904 WL12XX_MAX_RATE_POLICIES);
1905 if (policy >= WL12XX_MAX_RATE_POLICIES)
1906 return -EBUSY;
1907
1908 __set_bit(policy, wl->rate_policies_map);
1909 *idx = policy;
1910 return 0;
1911}
1912
1913static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1914{
1915 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1916 return;
1917
1918 __clear_bit(*idx, wl->rate_policies_map);
1919 *idx = WL12XX_MAX_RATE_POLICIES;
1920}
1921
Eliad Peller536129c2011-10-05 11:55:45 +02001922static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001923{
Eliad Peller536129c2011-10-05 11:55:45 +02001924 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001925 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001926 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001927 return WL1271_ROLE_P2P_GO;
1928 else
1929 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001930
1931 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001932 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001933 return WL1271_ROLE_P2P_CL;
1934 else
1935 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001936
Eliad Peller227e81e2011-08-14 13:17:26 +03001937 case BSS_TYPE_IBSS:
1938 return WL1271_ROLE_IBSS;
1939
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001940 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001941 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001942 }
1943 return WL12XX_INVALID_ROLE_TYPE;
1944}
1945
Eliad Peller83587502011-10-10 10:12:53 +02001946static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001947{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001948 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001949 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001950
Eliad Peller48e93e42011-10-10 10:12:58 +02001951 /* clear everything but the persistent data */
1952 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001953
1954 switch (ieee80211_vif_type_p2p(vif)) {
1955 case NL80211_IFTYPE_P2P_CLIENT:
1956 wlvif->p2p = 1;
1957 /* fall-through */
1958 case NL80211_IFTYPE_STATION:
1959 wlvif->bss_type = BSS_TYPE_STA_BSS;
1960 break;
1961 case NL80211_IFTYPE_ADHOC:
1962 wlvif->bss_type = BSS_TYPE_IBSS;
1963 break;
1964 case NL80211_IFTYPE_P2P_GO:
1965 wlvif->p2p = 1;
1966 /* fall-through */
1967 case NL80211_IFTYPE_AP:
1968 wlvif->bss_type = BSS_TYPE_AP_BSS;
1969 break;
1970 default:
1971 wlvif->bss_type = MAX_BSS_TYPE;
1972 return -EOPNOTSUPP;
1973 }
1974
Eliad Peller0603d892011-10-05 11:55:51 +02001975 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001976 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001977 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001978
Eliad Pellere936bbe2011-10-05 11:55:56 +02001979 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1980 wlvif->bss_type == BSS_TYPE_IBSS) {
1981 /* init sta/ibss data */
1982 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001983 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1984 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1985 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001986 } else {
1987 /* init ap data */
1988 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1989 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001990 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1991 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1992 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1993 wl12xx_allocate_rate_policy(wl,
1994 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001995 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001996
Eliad Peller83587502011-10-10 10:12:53 +02001997 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1998 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001999 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002000 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002001 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02002002 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
2003
Eliad Peller1b92f152011-10-10 10:13:09 +02002004 /*
2005 * mac80211 configures some values globally, while we treat them
2006 * per-interface. thus, on init, we have to copy them from wl
2007 */
2008 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02002009 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02002010 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02002011
Eliad Peller9eb599e2011-10-10 10:12:59 +02002012 INIT_WORK(&wlvif->rx_streaming_enable_work,
2013 wl1271_rx_streaming_enable_work);
2014 INIT_WORK(&wlvif->rx_streaming_disable_work,
2015 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02002016 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02002017 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02002018
Eliad Peller9eb599e2011-10-10 10:12:59 +02002019 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
2020 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002021 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002022}
2023
Eliad Peller1d095472011-10-10 10:12:49 +02002024static bool wl12xx_init_fw(struct wl1271 *wl)
2025{
2026 int retries = WL1271_BOOT_RETRIES;
2027 bool booted = false;
2028 struct wiphy *wiphy = wl->hw->wiphy;
2029 int ret;
2030
2031 while (retries) {
2032 retries--;
2033 ret = wl1271_chip_wakeup(wl);
2034 if (ret < 0)
2035 goto power_off;
2036
2037 ret = wl1271_boot(wl);
2038 if (ret < 0)
2039 goto power_off;
2040
2041 ret = wl1271_hw_init(wl);
2042 if (ret < 0)
2043 goto irq_disable;
2044
2045 booted = true;
2046 break;
2047
2048irq_disable:
2049 mutex_unlock(&wl->mutex);
2050 /* Unlocking the mutex in the middle of handling is
2051 inherently unsafe. In this case we deem it safe to do,
2052 because we need to let any possibly pending IRQ out of
2053 the system (and while we are WL1271_STATE_OFF the IRQ
2054 work function will not do anything.) Also, any other
2055 possible concurrent operations will fail due to the
2056 current state, hence the wl1271 struct should be safe. */
2057 wl1271_disable_interrupts(wl);
2058 wl1271_flush_deferred_work(wl);
2059 cancel_work_sync(&wl->netstack_work);
2060 mutex_lock(&wl->mutex);
2061power_off:
2062 wl1271_power_off(wl);
2063 }
2064
2065 if (!booted) {
2066 wl1271_error("firmware boot failed despite %d retries",
2067 WL1271_BOOT_RETRIES);
2068 goto out;
2069 }
2070
2071 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2072
2073 /* update hw/fw version info in wiphy struct */
2074 wiphy->hw_version = wl->chip.id;
2075 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2076 sizeof(wiphy->fw_version));
2077
2078 /*
2079 * Now we know if 11a is supported (info from the NVS), so disable
2080 * 11a channels if not supported
2081 */
2082 if (!wl->enable_11a)
2083 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2084
2085 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2086 wl->enable_11a ? "" : "not ");
2087
2088 wl->state = WL1271_STATE_ON;
2089out:
2090 return booted;
2091}
2092
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002093static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2094 struct ieee80211_vif *vif)
2095{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002096 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002097 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002098 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002099 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002100 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002101
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002102 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002103 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002104
2105 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002106 ret = wl1271_ps_elp_wakeup(wl);
2107 if (ret < 0)
2108 goto out_unlock;
2109
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002110 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002111 wl1271_debug(DEBUG_MAC80211,
2112 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002113 ret = -EBUSY;
2114 goto out;
2115 }
2116
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002117 /*
2118 * in some very corner case HW recovery scenarios its possible to
2119 * get here before __wl1271_op_remove_interface is complete, so
2120 * opt out if that is the case.
2121 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002122 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2123 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002124 ret = -EBUSY;
2125 goto out;
2126 }
2127
Eliad Peller83587502011-10-10 10:12:53 +02002128 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002129 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002130 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002131
Eliad Peller252efa42011-10-05 11:56:00 +02002132 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002133 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002134 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2135 ret = -EINVAL;
2136 goto out;
2137 }
Eliad Peller1d095472011-10-10 10:12:49 +02002138
Eliad Peller784f6942011-10-05 11:55:39 +02002139 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002140 * TODO: after the nvs issue will be solved, move this block
2141 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002142 */
Eliad Peller1d095472011-10-10 10:12:49 +02002143 if (wl->state == WL1271_STATE_OFF) {
2144 /*
2145 * we still need this in order to configure the fw
2146 * while uploading the nvs
2147 */
2148 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002149
Eliad Peller1d095472011-10-10 10:12:49 +02002150 booted = wl12xx_init_fw(wl);
2151 if (!booted) {
2152 ret = -EINVAL;
2153 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002154 }
Eliad Peller1d095472011-10-10 10:12:49 +02002155 }
Eliad Peller04e80792011-08-14 13:17:09 +03002156
Eliad Peller1d095472011-10-10 10:12:49 +02002157 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2158 wlvif->bss_type == BSS_TYPE_IBSS) {
2159 /*
2160 * The device role is a special role used for
2161 * rx and tx frames prior to association (as
2162 * the STA role can get packets only from
2163 * its associated bssid)
2164 */
Eliad Peller784f6942011-10-05 11:55:39 +02002165 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002166 WL1271_ROLE_DEVICE,
2167 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002168 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002169 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002170 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002171
Eliad Peller1d095472011-10-10 10:12:49 +02002172 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2173 role_type, &wlvif->role_id);
2174 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002175 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002176
2177 ret = wl1271_init_vif_specific(wl, vif);
2178 if (ret < 0)
2179 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002180
2181 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002182 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002183 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002184
2185 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2186 wl->ap_count++;
2187 else
2188 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002189out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002190 wl1271_ps_elp_sleep(wl);
2191out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002192 mutex_unlock(&wl->mutex);
2193
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002194 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002195 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002196 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002197 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002198
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002199 return ret;
2200}
2201
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002202static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002203 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002204 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002205{
Eliad Peller536129c2011-10-05 11:55:45 +02002206 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002207 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002208
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002209 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002210
Eliad Peller10c8cd02011-10-10 10:13:06 +02002211 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2212 return;
2213
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002214 /* because of hardware recovery, we may get here twice */
2215 if (wl->state != WL1271_STATE_ON)
2216 return;
2217
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002218 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002219
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002220 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002221 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002222 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002223
Eliad Pellerbaf62772011-10-10 10:12:52 +02002224 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2225 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002226 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002227 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002228 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002229 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002230 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002231 }
2232
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002233 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2234 /* disable active roles */
2235 ret = wl1271_ps_elp_wakeup(wl);
2236 if (ret < 0)
2237 goto deinit;
2238
Eliad Peller536129c2011-10-05 11:55:45 +02002239 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002240 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002241 if (ret < 0)
2242 goto deinit;
2243 }
2244
Eliad Peller0603d892011-10-05 11:55:51 +02002245 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002246 if (ret < 0)
2247 goto deinit;
2248
2249 wl1271_ps_elp_sleep(wl);
2250 }
2251deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002252 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002253 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002254
2255 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2256 wlvif->bss_type == BSS_TYPE_IBSS) {
2257 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2258 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2259 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2260 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2261 } else {
2262 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2263 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2264 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2265 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2266 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2267 wl12xx_free_rate_policy(wl,
2268 &wlvif->ap.ucast_rate_idx[i]);
2269 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002270
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002271 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002272 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002273 if (wl->last_wlvif == wlvif)
2274 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002275 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002276 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002277 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002278 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002279
Eliad Pellera4e41302011-10-11 11:49:15 +02002280 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2281 wl->ap_count--;
2282 else
2283 wl->sta_count--;
2284
Eliad Pellerbaf62772011-10-10 10:12:52 +02002285 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002286 del_timer_sync(&wlvif->rx_streaming_timer);
2287 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2288 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002289 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002290
Eliad Pellerbaf62772011-10-10 10:12:52 +02002291 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002292}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002293
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002294static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2295 struct ieee80211_vif *vif)
2296{
2297 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002298 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002299 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002300
2301 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002302
2303 if (wl->state == WL1271_STATE_OFF ||
2304 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2305 goto out;
2306
Juuso Oikarinen67353292010-11-18 15:19:02 +02002307 /*
2308 * wl->vif can be null here if someone shuts down the interface
2309 * just when hardware recovery has been started.
2310 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002311 wl12xx_for_each_wlvif(wl, iter) {
2312 if (iter != wlvif)
2313 continue;
2314
Eliad Peller536129c2011-10-05 11:55:45 +02002315 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002316 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002317 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002318 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002319out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002320 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002321 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002322}
2323
Eliad Peller87fbcb02011-10-05 11:55:41 +02002324static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2325 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002326{
2327 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002328 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002329
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002330 /*
2331 * One of the side effects of the JOIN command is that is clears
2332 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2333 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002334 * Currently the only valid scenario for JOIN during association
2335 * is on roaming, in which case we will also be given new keys.
2336 * Keep the below message for now, unless it starts bothering
2337 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002338 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002339 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002340 wl1271_info("JOIN while associated.");
2341
2342 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002343 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002344
Eliad Peller227e81e2011-08-14 13:17:26 +03002345 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002346 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002347 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002348 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002349 if (ret < 0)
2350 goto out;
2351
Eliad Pellerba8447f2011-10-10 10:13:00 +02002352 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002353 goto out;
2354
2355 /*
2356 * The join command disable the keep-alive mode, shut down its process,
2357 * and also clear the template config, so we need to reset it all after
2358 * the join. The acx_aid starts the keep-alive process, and the order
2359 * of the commands below is relevant.
2360 */
Eliad Peller0603d892011-10-05 11:55:51 +02002361 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002362 if (ret < 0)
2363 goto out;
2364
Eliad Peller0603d892011-10-05 11:55:51 +02002365 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002366 if (ret < 0)
2367 goto out;
2368
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002369 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002370 if (ret < 0)
2371 goto out;
2372
Eliad Peller0603d892011-10-05 11:55:51 +02002373 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2374 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002375 ACX_KEEP_ALIVE_TPL_VALID);
2376 if (ret < 0)
2377 goto out;
2378
2379out:
2380 return ret;
2381}
2382
Eliad Peller0603d892011-10-05 11:55:51 +02002383static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002384{
2385 int ret;
2386
Eliad Peller52630c52011-10-10 10:13:08 +02002387 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002388 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2389
Shahar Levi6d158ff2011-09-08 13:01:33 +03002390 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002391 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002392 }
2393
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002394 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002395 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002396 if (ret < 0)
2397 goto out;
2398
Oz Krakowskib992c682011-06-26 10:36:02 +03002399 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002400 wlvif->tx_security_last_seq_lsb = 0;
2401 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002402
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002403out:
2404 return ret;
2405}
2406
Eliad Peller87fbcb02011-10-05 11:55:41 +02002407static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002408{
Eliad Peller1b92f152011-10-10 10:13:09 +02002409 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002410 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002411}
2412
Eliad Peller251c1772011-08-14 13:17:17 +03002413static bool wl12xx_is_roc(struct wl1271 *wl)
2414{
2415 u8 role_id;
2416
2417 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2418 if (role_id >= WL12XX_MAX_ROLES)
2419 return false;
2420
2421 return true;
2422}
2423
Eliad Peller87fbcb02011-10-05 11:55:41 +02002424static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2425 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002426{
2427 int ret;
2428
2429 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002430 /* no need to croc if we weren't busy (e.g. during boot) */
2431 if (wl12xx_is_roc(wl)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002432 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002433 if (ret < 0)
2434 goto out;
2435 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002436 wlvif->rate_set =
2437 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2438 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002439 if (ret < 0)
2440 goto out;
2441 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002442 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002443 ACX_KEEP_ALIVE_TPL_INVALID);
2444 if (ret < 0)
2445 goto out;
2446 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2447 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002448 /* The current firmware only supports sched_scan in idle */
2449 if (wl->sched_scanning) {
2450 wl1271_scan_sched_scan_stop(wl);
2451 ieee80211_sched_scan_stopped(wl->hw);
2452 }
2453
Eliad Peller679a6732011-10-11 11:55:44 +02002454 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002455 if (ret < 0)
2456 goto out;
2457 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2458 }
2459
2460out:
2461 return ret;
2462}
2463
Eliad Peller9f259c42011-10-10 10:13:12 +02002464static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2465 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002466{
Eliad Peller9f259c42011-10-10 10:13:12 +02002467 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2468 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002469
2470 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2471
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002472 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002473 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002474 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002475 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002476 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002477 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002478 wlvif->band = conf->channel->band;
2479 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002480
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002481 if (!is_ap) {
2482 /*
2483 * FIXME: the mac80211 should really provide a fixed
2484 * rate to use here. for now, just use the smallest
2485 * possible rate for the band as a fixed rate for
2486 * association frames and other control messages.
2487 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002488 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002489 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002490
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002491 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002492 wl1271_tx_min_rate_get(wl,
2493 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002494 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002495 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002496 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002497 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002498
Eliad Pellerba8447f2011-10-10 10:13:00 +02002499 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2500 &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002501 if (wl12xx_is_roc(wl)) {
2502 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002503 ret = wl12xx_croc(wl,
2504 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002505 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002506 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002507 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002508 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002509 if (ret < 0)
2510 wl1271_warning("cmd join on channel "
2511 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002512 } else {
2513 /*
2514 * change the ROC channel. do it only if we are
2515 * not idle. otherwise, CROC will be called
2516 * anyway.
2517 */
2518 if (wl12xx_is_roc(wl) &&
2519 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002520 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002521 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002522 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002523
Eliad Peller679a6732011-10-11 11:55:44 +02002524 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002525 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002526 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002527 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002528 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002529 }
2530 }
2531
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002532 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002533 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002534 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002535 if (ret < 0)
2536 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002537 }
2538
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002539 /*
2540 * if mac80211 changes the PSM mode, make sure the mode is not
2541 * incorrectly changed after the pspoll failure active window.
2542 */
2543 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002544 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002545
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002546 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002547 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2548 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002549
2550 /*
2551 * We enter PSM only if we're already associated.
2552 * If we're not, we'll enter it when joining an SSID,
2553 * through the bss_info_changed() hook.
2554 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002555 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002556 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002557 ret = wl1271_ps_set_mode(wl, wlvif,
2558 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002559 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002560 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002561 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002562 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002563 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002564
Eliad Pellerc29bb002011-10-10 10:13:03 +02002565 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002566
Eliad Pellerc29bb002011-10-10 10:13:03 +02002567 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002568 ret = wl1271_ps_set_mode(wl, wlvif,
2569 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002570 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002571 }
2572
Eliad Peller6bd65022011-10-10 10:13:11 +02002573 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002574 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002575 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002576 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002577
Eliad Peller6bd65022011-10-10 10:13:11 +02002578 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002579 }
2580
Eliad Peller9f259c42011-10-10 10:13:12 +02002581 return 0;
2582}
2583
2584static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2585{
2586 struct wl1271 *wl = hw->priv;
2587 struct wl12xx_vif *wlvif;
2588 struct ieee80211_conf *conf = &hw->conf;
2589 int channel, ret = 0;
2590
2591 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2592
2593 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2594 " changed 0x%x",
2595 channel,
2596 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2597 conf->power_level,
2598 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2599 changed);
2600
2601 /*
2602 * mac80211 will go to idle nearly immediately after transmitting some
2603 * frames, such as the deauth. To make sure those frames reach the air,
2604 * wait here until the TX queue is fully flushed.
2605 */
2606 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2607 (conf->flags & IEEE80211_CONF_IDLE))
2608 wl1271_tx_flush(wl);
2609
2610 mutex_lock(&wl->mutex);
2611
2612 /* we support configuring the channel and band even while off */
2613 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2614 wl->band = conf->channel->band;
2615 wl->channel = channel;
2616 }
2617
2618 if (changed & IEEE80211_CONF_CHANGE_POWER)
2619 wl->power_level = conf->power_level;
2620
2621 if (unlikely(wl->state == WL1271_STATE_OFF))
2622 goto out;
2623
2624 ret = wl1271_ps_elp_wakeup(wl);
2625 if (ret < 0)
2626 goto out;
2627
2628 /* configure each interface */
2629 wl12xx_for_each_wlvif(wl, wlvif) {
2630 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2631 if (ret < 0)
2632 goto out_sleep;
2633 }
2634
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002635out_sleep:
2636 wl1271_ps_elp_sleep(wl);
2637
2638out:
2639 mutex_unlock(&wl->mutex);
2640
2641 return ret;
2642}
2643
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002644struct wl1271_filter_params {
2645 bool enabled;
2646 int mc_list_length;
2647 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2648};
2649
Jiri Pirko22bedad2010-04-01 21:22:57 +00002650static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2651 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002652{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002653 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002654 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002655 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002656
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002657 if (unlikely(wl->state == WL1271_STATE_OFF))
2658 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002659
Juuso Oikarinen74441132009-10-13 12:47:53 +03002660 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002661 if (!fp) {
2662 wl1271_error("Out of memory setting filters.");
2663 return 0;
2664 }
2665
2666 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002667 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002668 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2669 fp->enabled = false;
2670 } else {
2671 fp->enabled = true;
2672 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002673 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002674 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002675 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002676 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002677 }
2678
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002679 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002680}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002681
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002682#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2683 FIF_ALLMULTI | \
2684 FIF_FCSFAIL | \
2685 FIF_BCN_PRBRESP_PROMISC | \
2686 FIF_CONTROL | \
2687 FIF_OTHER_BSS)
2688
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002689static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2690 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002691 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002692{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002693 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002694 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002695 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002696
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002697 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002698
Arik Nemtsov7d057862010-10-16 19:25:35 +02002699 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2700 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002701
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002702 mutex_lock(&wl->mutex);
2703
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002704 *total &= WL1271_SUPPORTED_FILTERS;
2705 changed &= WL1271_SUPPORTED_FILTERS;
2706
2707 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002708 goto out;
2709
Ido Yariva6208652011-03-01 15:14:41 +02002710 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002711 if (ret < 0)
2712 goto out;
2713
Eliad Peller6e8cd332011-10-10 10:13:13 +02002714 wl12xx_for_each_wlvif(wl, wlvif) {
2715 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2716 if (*total & FIF_ALLMULTI)
2717 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2718 false,
2719 NULL, 0);
2720 else if (fp)
2721 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2722 fp->enabled,
2723 fp->mc_list,
2724 fp->mc_list_length);
2725 if (ret < 0)
2726 goto out_sleep;
2727 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002728 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002729
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002730 /*
2731 * the fw doesn't provide an api to configure the filters. instead,
2732 * the filters configuration is based on the active roles / ROC
2733 * state.
2734 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002735
2736out_sleep:
2737 wl1271_ps_elp_sleep(wl);
2738
2739out:
2740 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002741 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002742}
2743
Eliad Peller170d0e62011-10-05 11:56:06 +02002744static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2745 u8 id, u8 key_type, u8 key_size,
2746 const u8 *key, u8 hlid, u32 tx_seq_32,
2747 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002748{
2749 struct wl1271_ap_key *ap_key;
2750 int i;
2751
2752 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2753
2754 if (key_size > MAX_KEY_SIZE)
2755 return -EINVAL;
2756
2757 /*
2758 * Find next free entry in ap_keys. Also check we are not replacing
2759 * an existing key.
2760 */
2761 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002762 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002763 break;
2764
Eliad Peller170d0e62011-10-05 11:56:06 +02002765 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002766 wl1271_warning("trying to record key replacement");
2767 return -EINVAL;
2768 }
2769 }
2770
2771 if (i == MAX_NUM_KEYS)
2772 return -EBUSY;
2773
2774 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2775 if (!ap_key)
2776 return -ENOMEM;
2777
2778 ap_key->id = id;
2779 ap_key->key_type = key_type;
2780 ap_key->key_size = key_size;
2781 memcpy(ap_key->key, key, key_size);
2782 ap_key->hlid = hlid;
2783 ap_key->tx_seq_32 = tx_seq_32;
2784 ap_key->tx_seq_16 = tx_seq_16;
2785
Eliad Peller170d0e62011-10-05 11:56:06 +02002786 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002787 return 0;
2788}
2789
Eliad Peller170d0e62011-10-05 11:56:06 +02002790static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002791{
2792 int i;
2793
2794 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002795 kfree(wlvif->ap.recorded_keys[i]);
2796 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002797 }
2798}
2799
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002800static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002801{
2802 int i, ret = 0;
2803 struct wl1271_ap_key *key;
2804 bool wep_key_added = false;
2805
2806 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002807 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002808 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002809 break;
2810
Eliad Peller170d0e62011-10-05 11:56:06 +02002811 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002812 hlid = key->hlid;
2813 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002814 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002815
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002816 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002817 key->id, key->key_type,
2818 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002819 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002820 key->tx_seq_16);
2821 if (ret < 0)
2822 goto out;
2823
2824 if (key->key_type == KEY_WEP)
2825 wep_key_added = true;
2826 }
2827
2828 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002829 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002830 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002831 if (ret < 0)
2832 goto out;
2833 }
2834
2835out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002836 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002837 return ret;
2838}
2839
Eliad Peller536129c2011-10-05 11:55:45 +02002840static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2841 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002842 u8 key_size, const u8 *key, u32 tx_seq_32,
2843 u16 tx_seq_16, struct ieee80211_sta *sta)
2844{
2845 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002846 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002847
2848 if (is_ap) {
2849 struct wl1271_station *wl_sta;
2850 u8 hlid;
2851
2852 if (sta) {
2853 wl_sta = (struct wl1271_station *)sta->drv_priv;
2854 hlid = wl_sta->hlid;
2855 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002856 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002857 }
2858
Eliad Peller53d40d02011-10-10 10:13:02 +02002859 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002860 /*
2861 * We do not support removing keys after AP shutdown.
2862 * Pretend we do to make mac80211 happy.
2863 */
2864 if (action != KEY_ADD_OR_REPLACE)
2865 return 0;
2866
Eliad Peller170d0e62011-10-05 11:56:06 +02002867 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002868 key_type, key_size,
2869 key, hlid, tx_seq_32,
2870 tx_seq_16);
2871 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002872 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002873 id, key_type, key_size,
2874 key, hlid, tx_seq_32,
2875 tx_seq_16);
2876 }
2877
2878 if (ret < 0)
2879 return ret;
2880 } else {
2881 const u8 *addr;
2882 static const u8 bcast_addr[ETH_ALEN] = {
2883 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2884 };
2885
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002886 /*
2887 * A STA set to GEM cipher requires 2 tx spare blocks.
2888 * Return to default value when GEM cipher key is removed
2889 */
2890 if (key_type == KEY_GEM) {
2891 if (action == KEY_ADD_OR_REPLACE)
2892 wl->tx_spare_blocks = 2;
2893 else if (action == KEY_REMOVE)
2894 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2895 }
2896
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002897 addr = sta ? sta->addr : bcast_addr;
2898
2899 if (is_zero_ether_addr(addr)) {
2900 /* We dont support TX only encryption */
2901 return -EOPNOTSUPP;
2902 }
2903
2904 /* The wl1271 does not allow to remove unicast keys - they
2905 will be cleared automatically on next CMD_JOIN. Ignore the
2906 request silently, as we dont want the mac80211 to emit
2907 an error message. */
2908 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2909 return 0;
2910
Eliad Peller010d3d32011-08-14 13:17:31 +03002911 /* don't remove key if hlid was already deleted */
2912 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002913 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002914 return 0;
2915
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002916 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002917 id, key_type, key_size,
2918 key, addr, tx_seq_32,
2919 tx_seq_16);
2920 if (ret < 0)
2921 return ret;
2922
2923 /* the default WEP key needs to be configured at least once */
2924 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002925 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002926 wlvif->default_key,
2927 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002928 if (ret < 0)
2929 return ret;
2930 }
2931 }
2932
2933 return 0;
2934}
2935
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002936static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2937 struct ieee80211_vif *vif,
2938 struct ieee80211_sta *sta,
2939 struct ieee80211_key_conf *key_conf)
2940{
2941 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002942 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002943 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002944 u32 tx_seq_32 = 0;
2945 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002946 u8 key_type;
2947
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002948 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2949
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002950 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002951 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002952 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002953 key_conf->keylen, key_conf->flags);
2954 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002956 mutex_lock(&wl->mutex);
2957
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002958 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2959 ret = -EAGAIN;
2960 goto out_unlock;
2961 }
2962
Ido Yariva6208652011-03-01 15:14:41 +02002963 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002964 if (ret < 0)
2965 goto out_unlock;
2966
Johannes Berg97359d12010-08-10 09:46:38 +02002967 switch (key_conf->cipher) {
2968 case WLAN_CIPHER_SUITE_WEP40:
2969 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002970 key_type = KEY_WEP;
2971
2972 key_conf->hw_key_idx = key_conf->keyidx;
2973 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002974 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002975 key_type = KEY_TKIP;
2976
2977 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002978 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2979 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002980 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002981 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002982 key_type = KEY_AES;
2983
2984 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Eliad Peller48e93e42011-10-10 10:12:58 +02002985 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2986 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002987 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002988 case WL1271_CIPHER_SUITE_GEM:
2989 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002990 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2991 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002992 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002993 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002994 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002995
2996 ret = -EOPNOTSUPP;
2997 goto out_sleep;
2998 }
2999
3000 switch (cmd) {
3001 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003002 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003003 key_conf->keyidx, key_type,
3004 key_conf->keylen, key_conf->key,
3005 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003006 if (ret < 0) {
3007 wl1271_error("Could not add or replace key");
3008 goto out_sleep;
3009 }
3010 break;
3011
3012 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003013 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003014 key_conf->keyidx, key_type,
3015 key_conf->keylen, key_conf->key,
3016 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003017 if (ret < 0) {
3018 wl1271_error("Could not remove key");
3019 goto out_sleep;
3020 }
3021 break;
3022
3023 default:
3024 wl1271_error("Unsupported key cmd 0x%x", cmd);
3025 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003026 break;
3027 }
3028
3029out_sleep:
3030 wl1271_ps_elp_sleep(wl);
3031
3032out_unlock:
3033 mutex_unlock(&wl->mutex);
3034
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003035 return ret;
3036}
3037
3038static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003039 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003040 struct cfg80211_scan_request *req)
3041{
3042 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003043 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3044
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003045 int ret;
3046 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003047 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003048
3049 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3050
3051 if (req->n_ssids) {
3052 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003053 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003054 }
3055
3056 mutex_lock(&wl->mutex);
3057
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003058 if (wl->state == WL1271_STATE_OFF) {
3059 /*
3060 * We cannot return -EBUSY here because cfg80211 will expect
3061 * a call to ieee80211_scan_completed if we do - in this case
3062 * there won't be any call.
3063 */
3064 ret = -EAGAIN;
3065 goto out;
3066 }
3067
Ido Yariva6208652011-03-01 15:14:41 +02003068 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003069 if (ret < 0)
3070 goto out;
3071
Eliad Peller251c1772011-08-14 13:17:17 +03003072 /* cancel ROC before scanning */
3073 if (wl12xx_is_roc(wl)) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02003074 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03003075 /* don't allow scanning right now */
3076 ret = -EBUSY;
3077 goto out_sleep;
3078 }
Eliad Peller679a6732011-10-11 11:55:44 +02003079 wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003080 }
3081
Eliad Peller784f6942011-10-05 11:55:39 +02003082 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003083out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003084 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003085out:
3086 mutex_unlock(&wl->mutex);
3087
3088 return ret;
3089}
3090
Eliad Peller73ecce32011-06-27 13:06:45 +03003091static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3092 struct ieee80211_vif *vif)
3093{
3094 struct wl1271 *wl = hw->priv;
3095 int ret;
3096
3097 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3098
3099 mutex_lock(&wl->mutex);
3100
3101 if (wl->state == WL1271_STATE_OFF)
3102 goto out;
3103
3104 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3105 goto out;
3106
3107 ret = wl1271_ps_elp_wakeup(wl);
3108 if (ret < 0)
3109 goto out;
3110
3111 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3112 ret = wl1271_scan_stop(wl);
3113 if (ret < 0)
3114 goto out_sleep;
3115 }
3116 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3117 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003118 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003119 wl->scan.req = NULL;
3120 ieee80211_scan_completed(wl->hw, true);
3121
3122out_sleep:
3123 wl1271_ps_elp_sleep(wl);
3124out:
3125 mutex_unlock(&wl->mutex);
3126
3127 cancel_delayed_work_sync(&wl->scan_complete_work);
3128}
3129
Luciano Coelho33c2c062011-05-10 14:46:02 +03003130static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3131 struct ieee80211_vif *vif,
3132 struct cfg80211_sched_scan_request *req,
3133 struct ieee80211_sched_scan_ies *ies)
3134{
3135 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003136 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003137 int ret;
3138
3139 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3140
3141 mutex_lock(&wl->mutex);
3142
3143 ret = wl1271_ps_elp_wakeup(wl);
3144 if (ret < 0)
3145 goto out;
3146
Eliad Peller536129c2011-10-05 11:55:45 +02003147 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003148 if (ret < 0)
3149 goto out_sleep;
3150
Eliad Peller536129c2011-10-05 11:55:45 +02003151 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003152 if (ret < 0)
3153 goto out_sleep;
3154
3155 wl->sched_scanning = true;
3156
3157out_sleep:
3158 wl1271_ps_elp_sleep(wl);
3159out:
3160 mutex_unlock(&wl->mutex);
3161 return ret;
3162}
3163
3164static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3165 struct ieee80211_vif *vif)
3166{
3167 struct wl1271 *wl = hw->priv;
3168 int ret;
3169
3170 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3171
3172 mutex_lock(&wl->mutex);
3173
3174 ret = wl1271_ps_elp_wakeup(wl);
3175 if (ret < 0)
3176 goto out;
3177
3178 wl1271_scan_sched_scan_stop(wl);
3179
3180 wl1271_ps_elp_sleep(wl);
3181out:
3182 mutex_unlock(&wl->mutex);
3183}
3184
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003185static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3186{
3187 struct wl1271 *wl = hw->priv;
3188 int ret = 0;
3189
3190 mutex_lock(&wl->mutex);
3191
3192 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3193 ret = -EAGAIN;
3194 goto out;
3195 }
3196
Ido Yariva6208652011-03-01 15:14:41 +02003197 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003198 if (ret < 0)
3199 goto out;
3200
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003201 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003202 if (ret < 0)
3203 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3204
3205 wl1271_ps_elp_sleep(wl);
3206
3207out:
3208 mutex_unlock(&wl->mutex);
3209
3210 return ret;
3211}
3212
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003213static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3214{
3215 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003216 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003217 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003218
3219 mutex_lock(&wl->mutex);
3220
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003221 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3222 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003223 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003224 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003225
Ido Yariva6208652011-03-01 15:14:41 +02003226 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003227 if (ret < 0)
3228 goto out;
3229
Eliad Peller6e8cd332011-10-10 10:13:13 +02003230 wl12xx_for_each_wlvif(wl, wlvif) {
3231 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3232 if (ret < 0)
3233 wl1271_warning("set rts threshold failed: %d", ret);
3234 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003235 wl1271_ps_elp_sleep(wl);
3236
3237out:
3238 mutex_unlock(&wl->mutex);
3239
3240 return ret;
3241}
3242
Eliad Peller1fe9f162011-10-05 11:55:48 +02003243static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003244 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003245{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003246 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003247 u8 ssid_len;
3248 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3249 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003250
Eliad Peller889cb362011-05-01 09:56:45 +03003251 if (!ptr) {
3252 wl1271_error("No SSID in IEs!");
3253 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003254 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003255
Eliad Peller889cb362011-05-01 09:56:45 +03003256 ssid_len = ptr[1];
3257 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3258 wl1271_error("SSID is too long!");
3259 return -EINVAL;
3260 }
3261
Eliad Peller1fe9f162011-10-05 11:55:48 +02003262 wlvif->ssid_len = ssid_len;
3263 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003264 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003265}
3266
Eliad Pellerd48055d2011-09-15 12:07:04 +03003267static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3268{
3269 int len;
3270 const u8 *next, *end = skb->data + skb->len;
3271 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3272 skb->len - ieoffset);
3273 if (!ie)
3274 return;
3275 len = ie[1] + 2;
3276 next = ie + len;
3277 memmove(ie, next, end - next);
3278 skb_trim(skb, skb->len - len);
3279}
3280
Eliad Peller26b4bf22011-09-15 12:07:05 +03003281static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3282 unsigned int oui, u8 oui_type,
3283 int ieoffset)
3284{
3285 int len;
3286 const u8 *next, *end = skb->data + skb->len;
3287 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3288 skb->data + ieoffset,
3289 skb->len - ieoffset);
3290 if (!ie)
3291 return;
3292 len = ie[1] + 2;
3293 next = ie + len;
3294 memmove(ie, next, end - next);
3295 skb_trim(skb, skb->len - len);
3296}
3297
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003298static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
Eliad Peller1fe9f162011-10-05 11:55:48 +02003299 struct ieee80211_vif *vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003300 u8 *probe_rsp_data,
3301 size_t probe_rsp_len,
3302 u32 rates)
3303{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003304 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3305 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003306 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3307 int ssid_ie_offset, ie_offset, templ_len;
3308 const u8 *ptr;
3309
3310 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003311 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003312 return wl1271_cmd_template_set(wl,
3313 CMD_TEMPL_AP_PROBE_RESPONSE,
3314 probe_rsp_data,
3315 probe_rsp_len, 0,
3316 rates);
3317
3318 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3319 wl1271_error("probe_rsp template too big");
3320 return -EINVAL;
3321 }
3322
3323 /* start searching from IE offset */
3324 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3325
3326 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3327 probe_rsp_len - ie_offset);
3328 if (!ptr) {
3329 wl1271_error("No SSID in beacon!");
3330 return -EINVAL;
3331 }
3332
3333 ssid_ie_offset = ptr - probe_rsp_data;
3334 ptr += (ptr[1] + 2);
3335
3336 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3337
3338 /* insert SSID from bss_conf */
3339 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3340 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3341 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3342 bss_conf->ssid, bss_conf->ssid_len);
3343 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3344
3345 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3346 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3347 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3348
3349 return wl1271_cmd_template_set(wl,
3350 CMD_TEMPL_AP_PROBE_RESPONSE,
3351 probe_rsp_templ,
3352 templ_len, 0,
3353 rates);
3354}
3355
Arik Nemtsove78a2872010-10-16 19:07:21 +02003356static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003357 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003358 struct ieee80211_bss_conf *bss_conf,
3359 u32 changed)
3360{
Eliad Peller0603d892011-10-05 11:55:51 +02003361 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003362 int ret = 0;
3363
3364 if (changed & BSS_CHANGED_ERP_SLOT) {
3365 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003366 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003367 else
Eliad Peller0603d892011-10-05 11:55:51 +02003368 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003369 if (ret < 0) {
3370 wl1271_warning("Set slot time failed %d", ret);
3371 goto out;
3372 }
3373 }
3374
3375 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3376 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003377 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003378 else
Eliad Peller0603d892011-10-05 11:55:51 +02003379 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003380 }
3381
3382 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3383 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003384 ret = wl1271_acx_cts_protect(wl, wlvif,
3385 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003386 else
Eliad Peller0603d892011-10-05 11:55:51 +02003387 ret = wl1271_acx_cts_protect(wl, wlvif,
3388 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003389 if (ret < 0) {
3390 wl1271_warning("Set ctsprotect failed %d", ret);
3391 goto out;
3392 }
3393 }
3394
3395out:
3396 return ret;
3397}
3398
3399static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3400 struct ieee80211_vif *vif,
3401 struct ieee80211_bss_conf *bss_conf,
3402 u32 changed)
3403{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003404 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003405 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003406 int ret = 0;
3407
3408 if ((changed & BSS_CHANGED_BEACON_INT)) {
3409 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3410 bss_conf->beacon_int);
3411
Eliad Peller6a899792011-10-05 11:55:58 +02003412 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003413 }
3414
3415 if ((changed & BSS_CHANGED_BEACON)) {
3416 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003417 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003418 int ieoffset = offsetof(struct ieee80211_mgmt,
3419 u.beacon.variable);
3420 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3421 u16 tmpl_id;
3422
3423 if (!beacon)
3424 goto out;
3425
3426 wl1271_debug(DEBUG_MASTER, "beacon updated");
3427
Eliad Peller1fe9f162011-10-05 11:55:48 +02003428 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003429 if (ret < 0) {
3430 dev_kfree_skb(beacon);
3431 goto out;
3432 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003433 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003434 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3435 CMD_TEMPL_BEACON;
3436 ret = wl1271_cmd_template_set(wl, tmpl_id,
3437 beacon->data,
3438 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003439 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003440 if (ret < 0) {
3441 dev_kfree_skb(beacon);
3442 goto out;
3443 }
3444
Eliad Pellerd48055d2011-09-15 12:07:04 +03003445 /* remove TIM ie from probe response */
3446 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3447
Eliad Peller26b4bf22011-09-15 12:07:05 +03003448 /*
3449 * remove p2p ie from probe response.
3450 * the fw reponds to probe requests that don't include
3451 * the p2p ie. probe requests with p2p ie will be passed,
3452 * and will be responded by the supplicant (the spec
3453 * forbids including the p2p ie when responding to probe
3454 * requests that didn't include it).
3455 */
3456 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3457 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3458
Arik Nemtsove78a2872010-10-16 19:07:21 +02003459 hdr = (struct ieee80211_hdr *) beacon->data;
3460 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3461 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003462 if (is_ap)
Eliad Peller1fe9f162011-10-05 11:55:48 +02003463 ret = wl1271_ap_set_probe_resp_tmpl(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003464 beacon->data,
3465 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003466 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003467 else
3468 ret = wl1271_cmd_template_set(wl,
3469 CMD_TEMPL_PROBE_RESPONSE,
3470 beacon->data,
3471 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003472 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003473 dev_kfree_skb(beacon);
3474 if (ret < 0)
3475 goto out;
3476 }
3477
3478out:
3479 return ret;
3480}
3481
3482/* AP mode changes */
3483static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003484 struct ieee80211_vif *vif,
3485 struct ieee80211_bss_conf *bss_conf,
3486 u32 changed)
3487{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003488 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003489 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003490
Arik Nemtsove78a2872010-10-16 19:07:21 +02003491 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3492 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003493
Eliad Peller87fbcb02011-10-05 11:55:41 +02003494 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003495 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003496 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003497 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003498
Eliad Peller87fbcb02011-10-05 11:55:41 +02003499 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003500 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003501 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003502 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003503 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003504
Eliad Peller784f6942011-10-05 11:55:39 +02003505 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003506 if (ret < 0)
3507 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003508 }
3509
Arik Nemtsove78a2872010-10-16 19:07:21 +02003510 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3511 if (ret < 0)
3512 goto out;
3513
3514 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3515 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003516 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003517 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003518 if (ret < 0)
3519 goto out;
3520
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003521 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003522 if (ret < 0)
3523 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003524
Eliad Peller53d40d02011-10-10 10:13:02 +02003525 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003526 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003527 }
3528 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003529 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003530 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003531 if (ret < 0)
3532 goto out;
3533
Eliad Peller53d40d02011-10-10 10:13:02 +02003534 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003535 wl1271_debug(DEBUG_AP, "stopped AP");
3536 }
3537 }
3538 }
3539
Eliad Peller0603d892011-10-05 11:55:51 +02003540 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003541 if (ret < 0)
3542 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003543
3544 /* Handle HT information change */
3545 if ((changed & BSS_CHANGED_HT) &&
3546 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003547 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003548 bss_conf->ht_operation_mode);
3549 if (ret < 0) {
3550 wl1271_warning("Set ht information failed %d", ret);
3551 goto out;
3552 }
3553 }
3554
Arik Nemtsove78a2872010-10-16 19:07:21 +02003555out:
3556 return;
3557}
3558
3559/* STA/IBSS mode changes */
3560static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3561 struct ieee80211_vif *vif,
3562 struct ieee80211_bss_conf *bss_conf,
3563 u32 changed)
3564{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003565 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003566 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003567 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003568 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003569 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003570 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003571 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003572 bool sta_exists = false;
3573 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003574
3575 if (is_ibss) {
3576 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3577 changed);
3578 if (ret < 0)
3579 goto out;
3580 }
3581
Eliad Peller227e81e2011-08-14 13:17:26 +03003582 if (changed & BSS_CHANGED_IBSS) {
3583 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003584 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003585 ibss_joined = true;
3586 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003587 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3588 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003589 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003590 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003591 }
3592 }
3593 }
3594
3595 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003596 do_join = true;
3597
3598 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003599 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003600 do_join = true;
3601
Eliad Peller227e81e2011-08-14 13:17:26 +03003602 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003603 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3604 bss_conf->enable_beacon ? "enabled" : "disabled");
3605
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003606 do_join = true;
3607 }
3608
Arik Nemtsove78a2872010-10-16 19:07:21 +02003609 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003610 bool enable = false;
3611 if (bss_conf->cqm_rssi_thold)
3612 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003613 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003614 bss_conf->cqm_rssi_thold,
3615 bss_conf->cqm_rssi_hyst);
3616 if (ret < 0)
3617 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003618 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003619 }
3620
Eliad Pellercdf09492011-10-05 11:55:44 +02003621 if (changed & BSS_CHANGED_BSSID)
3622 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003623 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003624 if (ret < 0)
3625 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003626
Eliad Peller784f6942011-10-05 11:55:39 +02003627 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003628 if (ret < 0)
3629 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003630
Eliad Pellerfa287b82010-12-26 09:27:50 +01003631 /* Need to update the BSSID (for filtering etc) */
3632 do_join = true;
3633 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003634
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003635 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3636 rcu_read_lock();
3637 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3638 if (!sta)
3639 goto sta_not_found;
3640
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003641 /* save the supp_rates of the ap */
3642 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3643 if (sta->ht_cap.ht_supported)
3644 sta_rate_set |=
3645 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003646 sta_ht_cap = sta->ht_cap;
3647 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003648
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003649sta_not_found:
3650 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003651 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003652
Arik Nemtsove78a2872010-10-16 19:07:21 +02003653 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003654 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003655 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003656 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003657 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003658 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003659
Eliad Peller74ec8392011-10-05 11:56:02 +02003660 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003661
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003662 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003663 * use basic rates from AP, and determine lowest rate
3664 * to use with control frames.
3665 */
3666 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003667 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003668 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003669 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003670 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003671 wl1271_tx_min_rate_get(wl,
3672 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003673 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003674 wlvif->rate_set =
3675 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003676 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003677 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003678 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003679 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003680 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003681
3682 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003683 * with wl1271, we don't need to update the
3684 * beacon_int and dtim_period, because the firmware
3685 * updates it by itself when the first beacon is
3686 * received after a join.
3687 */
Eliad Peller6840e372011-10-05 11:55:50 +02003688 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003689 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003690 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003691
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003692 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003693 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003694 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003695 dev_kfree_skb(wlvif->probereq);
3696 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003697 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003698 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003699 ieoffset = offsetof(struct ieee80211_mgmt,
3700 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003701 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003702
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003703 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003704 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003705 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003706 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003707 } else {
3708 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003709 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003710 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3711 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003712 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003713 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3714 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003715 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003716
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003717 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003718 dev_kfree_skb(wlvif->probereq);
3719 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003720
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003721 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003722 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003723
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003724 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003725 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003726 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003727 wl1271_tx_min_rate_get(wl,
3728 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003729 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003730 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003731 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003732
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003733 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003734 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003735
3736 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003737 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003738 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003739 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003740
3741 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003742 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003743 u32 conf_flags = wl->hw->conf.flags;
3744 /*
3745 * we might have to disable roc, if there was
3746 * no IF_OPER_UP notification.
3747 */
3748 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003749 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003750 if (ret < 0)
3751 goto out;
3752 }
3753 /*
3754 * (we also need to disable roc in case of
3755 * roaming on the same channel. until we will
3756 * have a better flow...)
3757 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003758 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3759 ret = wl12xx_croc(wl,
3760 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003761 if (ret < 0)
3762 goto out;
3763 }
3764
Eliad Peller0603d892011-10-05 11:55:51 +02003765 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003766 if (!(conf_flags & IEEE80211_CONF_IDLE))
3767 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003768 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003769 }
3770 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003771
Eliad Pellerd192d262011-05-24 14:33:08 +03003772 if (changed & BSS_CHANGED_IBSS) {
3773 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3774 bss_conf->ibss_joined);
3775
3776 if (bss_conf->ibss_joined) {
3777 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003778 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003779 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003780 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003781 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003782 wl1271_tx_min_rate_get(wl,
3783 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003784
Shahar Levi06b660e2011-09-05 13:54:36 +03003785 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003786 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3787 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003788 if (ret < 0)
3789 goto out;
3790 }
3791 }
3792
Eliad Peller0603d892011-10-05 11:55:51 +02003793 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003794 if (ret < 0)
3795 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003796
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003797 if (changed & BSS_CHANGED_ARP_FILTER) {
3798 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003799 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003800
Eliad Pellerc5312772010-12-09 11:31:27 +02003801 if (bss_conf->arp_addr_cnt == 1 &&
3802 bss_conf->arp_filter_enabled) {
3803 /*
3804 * The template should have been configured only upon
3805 * association. however, it seems that the correct ip
3806 * isn't being set (when sending), so we have to
3807 * reconfigure the template upon every ip change.
3808 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003809 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003810 if (ret < 0) {
3811 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003812 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003813 }
3814
Eliad Peller0603d892011-10-05 11:55:51 +02003815 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003816 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003817 addr);
3818 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003819 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003820
3821 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003822 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003823 }
3824
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003825 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003826 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003827 if (ret < 0) {
3828 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003829 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003830 }
Eliad Peller251c1772011-08-14 13:17:17 +03003831
3832 /* ROC until connected (after EAPOL exchange) */
3833 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003834 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003835 if (ret < 0)
3836 goto out;
3837
Eliad Pellerba8447f2011-10-10 10:13:00 +02003838 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003839 ieee80211_get_operstate(vif));
3840 }
3841 /*
3842 * stop device role if started (we might already be in
3843 * STA role). TODO: make it better.
3844 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003845 if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) {
Eliad Peller679a6732011-10-11 11:55:44 +02003846 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003847 if (ret < 0)
3848 goto out;
3849 }
Eliad Peller05dba352011-08-23 16:37:01 +03003850
3851 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003852 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3853 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003854 enum wl1271_cmd_ps_mode mode;
3855
3856 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003857 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003858 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003859 true);
3860 if (ret < 0)
3861 goto out;
3862 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003863 }
3864
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003865 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003866 if (sta_exists) {
3867 if ((changed & BSS_CHANGED_HT) &&
3868 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003869 ret = wl1271_acx_set_ht_capabilities(wl,
3870 &sta_ht_cap,
3871 true,
Eliad Peller154da672011-10-05 11:55:53 +02003872 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003873 if (ret < 0) {
3874 wl1271_warning("Set ht cap true failed %d",
3875 ret);
3876 goto out;
3877 }
3878 }
3879 /* handle new association without HT and disassociation */
3880 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003881 ret = wl1271_acx_set_ht_capabilities(wl,
3882 &sta_ht_cap,
3883 false,
Eliad Peller154da672011-10-05 11:55:53 +02003884 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003885 if (ret < 0) {
3886 wl1271_warning("Set ht cap false failed %d",
3887 ret);
3888 goto out;
3889 }
3890 }
3891 }
3892
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003893 /* Handle HT information change. Done after join. */
3894 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003895 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003896 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003897 bss_conf->ht_operation_mode);
3898 if (ret < 0) {
3899 wl1271_warning("Set ht information failed %d", ret);
3900 goto out;
3901 }
3902 }
3903
Arik Nemtsove78a2872010-10-16 19:07:21 +02003904out:
3905 return;
3906}
3907
3908static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3909 struct ieee80211_vif *vif,
3910 struct ieee80211_bss_conf *bss_conf,
3911 u32 changed)
3912{
3913 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003914 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3915 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003916 int ret;
3917
3918 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3919 (int)changed);
3920
3921 mutex_lock(&wl->mutex);
3922
3923 if (unlikely(wl->state == WL1271_STATE_OFF))
3924 goto out;
3925
Eliad Peller10c8cd02011-10-10 10:13:06 +02003926 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3927 goto out;
3928
Ido Yariva6208652011-03-01 15:14:41 +02003929 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003930 if (ret < 0)
3931 goto out;
3932
3933 if (is_ap)
3934 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3935 else
3936 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3937
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003938 wl1271_ps_elp_sleep(wl);
3939
3940out:
3941 mutex_unlock(&wl->mutex);
3942}
3943
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003944static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3945 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003946 const struct ieee80211_tx_queue_params *params)
3947{
3948 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003949 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003950 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003951 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003952
3953 mutex_lock(&wl->mutex);
3954
3955 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3956
Kalle Valo4695dc92010-03-18 12:26:38 +02003957 if (params->uapsd)
3958 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3959 else
3960 ps_scheme = CONF_PS_SCHEME_LEGACY;
3961
Arik Nemtsov488fc542010-10-16 20:33:45 +02003962 if (wl->state == WL1271_STATE_OFF) {
3963 /*
3964 * If the state is off, the parameters will be recorded and
3965 * configured on init. This happens in AP-mode.
3966 */
3967 struct conf_tx_ac_category *conf_ac =
3968 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3969 struct conf_tx_tid *conf_tid =
3970 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3971
3972 conf_ac->ac = wl1271_tx_get_queue(queue);
3973 conf_ac->cw_min = (u8)params->cw_min;
3974 conf_ac->cw_max = params->cw_max;
3975 conf_ac->aifsn = params->aifs;
3976 conf_ac->tx_op_limit = params->txop << 5;
3977
3978 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3979 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3980 conf_tid->tsid = wl1271_tx_get_queue(queue);
3981 conf_tid->ps_scheme = ps_scheme;
3982 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3983 conf_tid->apsd_conf[0] = 0;
3984 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003985 goto out;
3986 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003987
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003988 ret = wl1271_ps_elp_wakeup(wl);
3989 if (ret < 0)
3990 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003991
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003992 /*
3993 * the txop is confed in units of 32us by the mac80211,
3994 * we need us
3995 */
Eliad Peller0603d892011-10-05 11:55:51 +02003996 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003997 params->cw_min, params->cw_max,
3998 params->aifs, params->txop << 5);
3999 if (ret < 0)
4000 goto out_sleep;
4001
Eliad Peller0603d892011-10-05 11:55:51 +02004002 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004003 CONF_CHANNEL_TYPE_EDCF,
4004 wl1271_tx_get_queue(queue),
4005 ps_scheme, CONF_ACK_POLICY_LEGACY,
4006 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004007
4008out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004009 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004010
4011out:
4012 mutex_unlock(&wl->mutex);
4013
4014 return ret;
4015}
4016
Eliad Peller37a41b42011-09-21 14:06:11 +03004017static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4018 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004019{
4020
4021 struct wl1271 *wl = hw->priv;
4022 u64 mactime = ULLONG_MAX;
4023 int ret;
4024
4025 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4026
4027 mutex_lock(&wl->mutex);
4028
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004029 if (unlikely(wl->state == WL1271_STATE_OFF))
4030 goto out;
4031
Ido Yariva6208652011-03-01 15:14:41 +02004032 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004033 if (ret < 0)
4034 goto out;
4035
4036 ret = wl1271_acx_tsf_info(wl, &mactime);
4037 if (ret < 0)
4038 goto out_sleep;
4039
4040out_sleep:
4041 wl1271_ps_elp_sleep(wl);
4042
4043out:
4044 mutex_unlock(&wl->mutex);
4045 return mactime;
4046}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004047
John W. Linvilleece550d2010-07-28 16:41:06 -04004048static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4049 struct survey_info *survey)
4050{
4051 struct wl1271 *wl = hw->priv;
4052 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004053
John W. Linvilleece550d2010-07-28 16:41:06 -04004054 if (idx != 0)
4055 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004056
John W. Linvilleece550d2010-07-28 16:41:06 -04004057 survey->channel = conf->channel;
4058 survey->filled = SURVEY_INFO_NOISE_DBM;
4059 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004060
John W. Linvilleece550d2010-07-28 16:41:06 -04004061 return 0;
4062}
4063
Arik Nemtsov409622e2011-02-23 00:22:29 +02004064static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004065 struct wl12xx_vif *wlvif,
4066 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004067{
4068 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004069 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004070
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004071
4072 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004073 wl1271_warning("could not allocate HLID - too much stations");
4074 return -EBUSY;
4075 }
4076
4077 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004078 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4079 if (ret < 0) {
4080 wl1271_warning("could not allocate HLID - too many links");
4081 return -EBUSY;
4082 }
4083
4084 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004085 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004086 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004087 return 0;
4088}
4089
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004090void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004091{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004092 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004093 return;
4094
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004095 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004096 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004097 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004098 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004099 __clear_bit(hlid, &wl->ap_ps_map);
4100 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004101 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004102 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004103}
4104
4105static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4106 struct ieee80211_vif *vif,
4107 struct ieee80211_sta *sta)
4108{
4109 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004110 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004111 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004112 int ret = 0;
4113 u8 hlid;
4114
4115 mutex_lock(&wl->mutex);
4116
4117 if (unlikely(wl->state == WL1271_STATE_OFF))
4118 goto out;
4119
Eliad Peller536129c2011-10-05 11:55:45 +02004120 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004121 goto out;
4122
4123 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4124
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004125 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004126 if (ret < 0)
4127 goto out;
4128
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004129 wl_sta = (struct wl1271_station *)sta->drv_priv;
4130 hlid = wl_sta->hlid;
4131
Ido Yariva6208652011-03-01 15:14:41 +02004132 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004133 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004134 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004135
Eliad Peller1b92f152011-10-10 10:13:09 +02004136 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004137 if (ret < 0)
4138 goto out_sleep;
4139
Eliad Pellerb67476e2011-08-14 13:17:23 +03004140 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4141 if (ret < 0)
4142 goto out_sleep;
4143
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004144 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4145 if (ret < 0)
4146 goto out_sleep;
4147
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004148out_sleep:
4149 wl1271_ps_elp_sleep(wl);
4150
Arik Nemtsov409622e2011-02-23 00:22:29 +02004151out_free_sta:
4152 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004153 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004154
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004155out:
4156 mutex_unlock(&wl->mutex);
4157 return ret;
4158}
4159
4160static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4161 struct ieee80211_vif *vif,
4162 struct ieee80211_sta *sta)
4163{
4164 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004165 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004166 struct wl1271_station *wl_sta;
4167 int ret = 0, id;
4168
4169 mutex_lock(&wl->mutex);
4170
4171 if (unlikely(wl->state == WL1271_STATE_OFF))
4172 goto out;
4173
Eliad Peller536129c2011-10-05 11:55:45 +02004174 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004175 goto out;
4176
4177 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4178
4179 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004180 id = wl_sta->hlid;
4181 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004182 goto out;
4183
Ido Yariva6208652011-03-01 15:14:41 +02004184 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004185 if (ret < 0)
4186 goto out;
4187
Eliad Pellerc690ec82011-08-14 13:17:07 +03004188 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004189 if (ret < 0)
4190 goto out_sleep;
4191
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004192 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004193
4194out_sleep:
4195 wl1271_ps_elp_sleep(wl);
4196
4197out:
4198 mutex_unlock(&wl->mutex);
4199 return ret;
4200}
4201
Luciano Coelho4623ec72011-03-21 19:26:41 +02004202static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4203 struct ieee80211_vif *vif,
4204 enum ieee80211_ampdu_mlme_action action,
4205 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4206 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004207{
4208 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004209 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004210 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004211 u8 hlid, *ba_bitmap;
4212
4213 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4214 tid);
4215
4216 /* sanity check - the fields in FW are only 8bits wide */
4217 if (WARN_ON(tid > 0xFF))
4218 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004219
4220 mutex_lock(&wl->mutex);
4221
4222 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4223 ret = -EAGAIN;
4224 goto out;
4225 }
4226
Eliad Peller536129c2011-10-05 11:55:45 +02004227 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004228 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004229 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004230 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004231 struct wl1271_station *wl_sta;
4232
4233 wl_sta = (struct wl1271_station *)sta->drv_priv;
4234 hlid = wl_sta->hlid;
4235 ba_bitmap = &wl->links[hlid].ba_bitmap;
4236 } else {
4237 ret = -EINVAL;
4238 goto out;
4239 }
4240
Ido Yariva6208652011-03-01 15:14:41 +02004241 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004242 if (ret < 0)
4243 goto out;
4244
Shahar Levi70559a02011-05-22 16:10:22 +03004245 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4246 tid, action);
4247
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004248 switch (action) {
4249 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004250 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004251 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004252 break;
4253 }
4254
4255 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4256 ret = -EBUSY;
4257 wl1271_error("exceeded max RX BA sessions");
4258 break;
4259 }
4260
4261 if (*ba_bitmap & BIT(tid)) {
4262 ret = -EINVAL;
4263 wl1271_error("cannot enable RX BA session on active "
4264 "tid: %d", tid);
4265 break;
4266 }
4267
4268 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4269 hlid);
4270 if (!ret) {
4271 *ba_bitmap |= BIT(tid);
4272 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004273 }
4274 break;
4275
4276 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004277 if (!(*ba_bitmap & BIT(tid))) {
4278 ret = -EINVAL;
4279 wl1271_error("no active RX BA session on tid: %d",
4280 tid);
4281 break;
4282 }
4283
4284 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4285 hlid);
4286 if (!ret) {
4287 *ba_bitmap &= ~BIT(tid);
4288 wl->ba_rx_session_count--;
4289 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004290 break;
4291
4292 /*
4293 * The BA initiator session management in FW independently.
4294 * Falling break here on purpose for all TX APDU commands.
4295 */
4296 case IEEE80211_AMPDU_TX_START:
4297 case IEEE80211_AMPDU_TX_STOP:
4298 case IEEE80211_AMPDU_TX_OPERATIONAL:
4299 ret = -EINVAL;
4300 break;
4301
4302 default:
4303 wl1271_error("Incorrect ampdu action id=%x\n", action);
4304 ret = -EINVAL;
4305 }
4306
4307 wl1271_ps_elp_sleep(wl);
4308
4309out:
4310 mutex_unlock(&wl->mutex);
4311
4312 return ret;
4313}
4314
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004315static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4316 struct ieee80211_vif *vif,
4317 const struct cfg80211_bitrate_mask *mask)
4318{
Eliad Peller83587502011-10-10 10:12:53 +02004319 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004320 struct wl1271 *wl = hw->priv;
4321 int i;
4322
4323 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4324 mask->control[NL80211_BAND_2GHZ].legacy,
4325 mask->control[NL80211_BAND_5GHZ].legacy);
4326
4327 mutex_lock(&wl->mutex);
4328
4329 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004330 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004331 wl1271_tx_enabled_rates_get(wl,
4332 mask->control[i].legacy,
4333 i);
4334 mutex_unlock(&wl->mutex);
4335
4336 return 0;
4337}
4338
Shahar Levi6d158ff2011-09-08 13:01:33 +03004339static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4340 struct ieee80211_channel_switch *ch_switch)
4341{
4342 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004343 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004344 int ret;
4345
4346 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4347
4348 mutex_lock(&wl->mutex);
4349
4350 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004351 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4352 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4353 ieee80211_chswitch_done(vif, false);
4354 }
4355 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004356 }
4357
4358 ret = wl1271_ps_elp_wakeup(wl);
4359 if (ret < 0)
4360 goto out;
4361
Eliad Peller52630c52011-10-10 10:13:08 +02004362 /* TODO: change mac80211 to pass vif as param */
4363 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4364 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004365
Eliad Peller52630c52011-10-10 10:13:08 +02004366 if (!ret)
4367 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4368 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004369
4370 wl1271_ps_elp_sleep(wl);
4371
4372out:
4373 mutex_unlock(&wl->mutex);
4374}
4375
Arik Nemtsov33437892011-04-26 23:35:39 +03004376static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4377{
4378 struct wl1271 *wl = hw->priv;
4379 bool ret = false;
4380
4381 mutex_lock(&wl->mutex);
4382
4383 if (unlikely(wl->state == WL1271_STATE_OFF))
4384 goto out;
4385
4386 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004387 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004388out:
4389 mutex_unlock(&wl->mutex);
4390
4391 return ret;
4392}
4393
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004394/* can't be const, mac80211 writes to this */
4395static struct ieee80211_rate wl1271_rates[] = {
4396 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004397 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4398 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004399 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004400 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4401 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004402 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4403 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004404 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4405 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004406 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4407 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004408 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4409 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004410 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4411 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004412 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4413 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004414 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004415 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4416 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004417 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004418 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4419 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004420 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004421 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4422 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004423 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004424 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4425 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004426 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004427 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4428 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004429 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004430 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4431 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004432 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004433 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4434 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004435};
4436
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004437/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004438static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004439 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004440 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004441 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4442 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4443 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004444 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004445 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4446 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4447 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004448 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004449 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4450 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4451 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004452 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004453};
4454
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004455/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004456static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004457 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004458 7, /* CONF_HW_RXTX_RATE_MCS7 */
4459 6, /* CONF_HW_RXTX_RATE_MCS6 */
4460 5, /* CONF_HW_RXTX_RATE_MCS5 */
4461 4, /* CONF_HW_RXTX_RATE_MCS4 */
4462 3, /* CONF_HW_RXTX_RATE_MCS3 */
4463 2, /* CONF_HW_RXTX_RATE_MCS2 */
4464 1, /* CONF_HW_RXTX_RATE_MCS1 */
4465 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004466
4467 11, /* CONF_HW_RXTX_RATE_54 */
4468 10, /* CONF_HW_RXTX_RATE_48 */
4469 9, /* CONF_HW_RXTX_RATE_36 */
4470 8, /* CONF_HW_RXTX_RATE_24 */
4471
4472 /* TI-specific rate */
4473 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4474
4475 7, /* CONF_HW_RXTX_RATE_18 */
4476 6, /* CONF_HW_RXTX_RATE_12 */
4477 3, /* CONF_HW_RXTX_RATE_11 */
4478 5, /* CONF_HW_RXTX_RATE_9 */
4479 4, /* CONF_HW_RXTX_RATE_6 */
4480 2, /* CONF_HW_RXTX_RATE_5_5 */
4481 1, /* CONF_HW_RXTX_RATE_2 */
4482 0 /* CONF_HW_RXTX_RATE_1 */
4483};
4484
Shahar Levie8b03a22010-10-13 16:09:39 +02004485/* 11n STA capabilities */
4486#define HW_RX_HIGHEST_RATE 72
4487
Shahar Levi00d20102010-11-08 11:20:10 +00004488#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004489 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4490 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004491 .ht_supported = true, \
4492 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4493 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4494 .mcs = { \
4495 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4496 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4497 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4498 }, \
4499}
4500
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004501/* can't be const, mac80211 writes to this */
4502static struct ieee80211_supported_band wl1271_band_2ghz = {
4503 .channels = wl1271_channels,
4504 .n_channels = ARRAY_SIZE(wl1271_channels),
4505 .bitrates = wl1271_rates,
4506 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004507 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004508};
4509
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004510/* 5 GHz data rates for WL1273 */
4511static struct ieee80211_rate wl1271_rates_5ghz[] = {
4512 { .bitrate = 60,
4513 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4514 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4515 { .bitrate = 90,
4516 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4517 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4518 { .bitrate = 120,
4519 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4520 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4521 { .bitrate = 180,
4522 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4523 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4524 { .bitrate = 240,
4525 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4526 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4527 { .bitrate = 360,
4528 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4529 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4530 { .bitrate = 480,
4531 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4532 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4533 { .bitrate = 540,
4534 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4535 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4536};
4537
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004538/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004539static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004540 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4541 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4542 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4543 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4544 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4545 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4546 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4547 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4548 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4549 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4550 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4551 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4552 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4553 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4554 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4555 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4556 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4557 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4558 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4559 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4560 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4561 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4562 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4563 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4564 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4565 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4566 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4567 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4568 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4569 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4570 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4571 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4572 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4573 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004574};
4575
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004576/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004577static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004578 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004579 7, /* CONF_HW_RXTX_RATE_MCS7 */
4580 6, /* CONF_HW_RXTX_RATE_MCS6 */
4581 5, /* CONF_HW_RXTX_RATE_MCS5 */
4582 4, /* CONF_HW_RXTX_RATE_MCS4 */
4583 3, /* CONF_HW_RXTX_RATE_MCS3 */
4584 2, /* CONF_HW_RXTX_RATE_MCS2 */
4585 1, /* CONF_HW_RXTX_RATE_MCS1 */
4586 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004587
4588 7, /* CONF_HW_RXTX_RATE_54 */
4589 6, /* CONF_HW_RXTX_RATE_48 */
4590 5, /* CONF_HW_RXTX_RATE_36 */
4591 4, /* CONF_HW_RXTX_RATE_24 */
4592
4593 /* TI-specific rate */
4594 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4595
4596 3, /* CONF_HW_RXTX_RATE_18 */
4597 2, /* CONF_HW_RXTX_RATE_12 */
4598 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4599 1, /* CONF_HW_RXTX_RATE_9 */
4600 0, /* CONF_HW_RXTX_RATE_6 */
4601 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4602 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4603 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4604};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004605
4606static struct ieee80211_supported_band wl1271_band_5ghz = {
4607 .channels = wl1271_channels_5ghz,
4608 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4609 .bitrates = wl1271_rates_5ghz,
4610 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004611 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004612};
4613
Tobias Klausera0ea9492010-05-20 10:38:11 +02004614static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004615 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4616 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4617};
4618
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004619static const struct ieee80211_ops wl1271_ops = {
4620 .start = wl1271_op_start,
4621 .stop = wl1271_op_stop,
4622 .add_interface = wl1271_op_add_interface,
4623 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004624#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004625 .suspend = wl1271_op_suspend,
4626 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004627#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004628 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004629 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004630 .configure_filter = wl1271_op_configure_filter,
4631 .tx = wl1271_op_tx,
4632 .set_key = wl1271_op_set_key,
4633 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004634 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004635 .sched_scan_start = wl1271_op_sched_scan_start,
4636 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004637 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004638 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004639 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004640 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004641 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004642 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004643 .sta_add = wl1271_op_sta_add,
4644 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004645 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004646 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004647 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004648 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004649 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004650};
4651
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004652
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004653u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004654{
4655 u8 idx;
4656
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004657 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004658
4659 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4660 wl1271_error("Illegal RX rate from HW: %d", rate);
4661 return 0;
4662 }
4663
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004664 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004665 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4666 wl1271_error("Unsupported RX rate from HW: %d", rate);
4667 return 0;
4668 }
4669
4670 return idx;
4671}
4672
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004673static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4674 struct device_attribute *attr,
4675 char *buf)
4676{
4677 struct wl1271 *wl = dev_get_drvdata(dev);
4678 ssize_t len;
4679
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004680 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004681
4682 mutex_lock(&wl->mutex);
4683 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4684 wl->sg_enabled);
4685 mutex_unlock(&wl->mutex);
4686
4687 return len;
4688
4689}
4690
4691static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4692 struct device_attribute *attr,
4693 const char *buf, size_t count)
4694{
4695 struct wl1271 *wl = dev_get_drvdata(dev);
4696 unsigned long res;
4697 int ret;
4698
Luciano Coelho6277ed62011-04-01 17:49:54 +03004699 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004700 if (ret < 0) {
4701 wl1271_warning("incorrect value written to bt_coex_mode");
4702 return count;
4703 }
4704
4705 mutex_lock(&wl->mutex);
4706
4707 res = !!res;
4708
4709 if (res == wl->sg_enabled)
4710 goto out;
4711
4712 wl->sg_enabled = res;
4713
4714 if (wl->state == WL1271_STATE_OFF)
4715 goto out;
4716
Ido Yariva6208652011-03-01 15:14:41 +02004717 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004718 if (ret < 0)
4719 goto out;
4720
4721 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4722 wl1271_ps_elp_sleep(wl);
4723
4724 out:
4725 mutex_unlock(&wl->mutex);
4726 return count;
4727}
4728
4729static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4730 wl1271_sysfs_show_bt_coex_state,
4731 wl1271_sysfs_store_bt_coex_state);
4732
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004733static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4734 struct device_attribute *attr,
4735 char *buf)
4736{
4737 struct wl1271 *wl = dev_get_drvdata(dev);
4738 ssize_t len;
4739
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004740 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004741
4742 mutex_lock(&wl->mutex);
4743 if (wl->hw_pg_ver >= 0)
4744 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4745 else
4746 len = snprintf(buf, len, "n/a\n");
4747 mutex_unlock(&wl->mutex);
4748
4749 return len;
4750}
4751
Gery Kahn6f07b722011-07-18 14:21:49 +03004752static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004753 wl1271_sysfs_show_hw_pg_ver, NULL);
4754
Ido Yariv95dac04f2011-06-06 14:57:06 +03004755static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4756 struct bin_attribute *bin_attr,
4757 char *buffer, loff_t pos, size_t count)
4758{
4759 struct device *dev = container_of(kobj, struct device, kobj);
4760 struct wl1271 *wl = dev_get_drvdata(dev);
4761 ssize_t len;
4762 int ret;
4763
4764 ret = mutex_lock_interruptible(&wl->mutex);
4765 if (ret < 0)
4766 return -ERESTARTSYS;
4767
4768 /* Let only one thread read the log at a time, blocking others */
4769 while (wl->fwlog_size == 0) {
4770 DEFINE_WAIT(wait);
4771
4772 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4773 &wait,
4774 TASK_INTERRUPTIBLE);
4775
4776 if (wl->fwlog_size != 0) {
4777 finish_wait(&wl->fwlog_waitq, &wait);
4778 break;
4779 }
4780
4781 mutex_unlock(&wl->mutex);
4782
4783 schedule();
4784 finish_wait(&wl->fwlog_waitq, &wait);
4785
4786 if (signal_pending(current))
4787 return -ERESTARTSYS;
4788
4789 ret = mutex_lock_interruptible(&wl->mutex);
4790 if (ret < 0)
4791 return -ERESTARTSYS;
4792 }
4793
4794 /* Check if the fwlog is still valid */
4795 if (wl->fwlog_size < 0) {
4796 mutex_unlock(&wl->mutex);
4797 return 0;
4798 }
4799
4800 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4801 len = min(count, (size_t)wl->fwlog_size);
4802 wl->fwlog_size -= len;
4803 memcpy(buffer, wl->fwlog, len);
4804
4805 /* Make room for new messages */
4806 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4807
4808 mutex_unlock(&wl->mutex);
4809
4810 return len;
4811}
4812
4813static struct bin_attribute fwlog_attr = {
4814 .attr = {.name = "fwlog", .mode = S_IRUSR},
4815 .read = wl1271_sysfs_read_fwlog,
4816};
4817
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004818static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004819{
4820 int ret;
4821
4822 if (wl->mac80211_registered)
4823 return 0;
4824
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004825 ret = wl1271_fetch_nvs(wl);
4826 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004827 /* NOTE: The wl->nvs->nvs element must be first, in
4828 * order to simplify the casting, we assume it is at
4829 * the beginning of the wl->nvs structure.
4830 */
4831 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004832
4833 wl->mac_addr[0] = nvs_ptr[11];
4834 wl->mac_addr[1] = nvs_ptr[10];
4835 wl->mac_addr[2] = nvs_ptr[6];
4836 wl->mac_addr[3] = nvs_ptr[5];
4837 wl->mac_addr[4] = nvs_ptr[4];
4838 wl->mac_addr[5] = nvs_ptr[3];
4839 }
4840
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004841 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4842
4843 ret = ieee80211_register_hw(wl->hw);
4844 if (ret < 0) {
4845 wl1271_error("unable to register mac80211 hw: %d", ret);
4846 return ret;
4847 }
4848
4849 wl->mac80211_registered = true;
4850
Eliad Pellerd60080a2010-11-24 12:53:16 +02004851 wl1271_debugfs_init(wl);
4852
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004853 register_netdevice_notifier(&wl1271_dev_notifier);
4854
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004855 wl1271_notice("loaded");
4856
4857 return 0;
4858}
4859
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004860static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004861{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004862 if (wl->state == WL1271_STATE_PLT)
4863 __wl1271_plt_stop(wl);
4864
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004865 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004866 ieee80211_unregister_hw(wl->hw);
4867 wl->mac80211_registered = false;
4868
4869}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004870
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004871static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004872{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004873 static const u32 cipher_suites[] = {
4874 WLAN_CIPHER_SUITE_WEP40,
4875 WLAN_CIPHER_SUITE_WEP104,
4876 WLAN_CIPHER_SUITE_TKIP,
4877 WLAN_CIPHER_SUITE_CCMP,
4878 WL1271_CIPHER_SUITE_GEM,
4879 };
4880
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004881 /* The tx descriptor buffer and the TKIP space. */
4882 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4883 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004884
4885 /* unit us */
4886 /* FIXME: find a proper value */
4887 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004888 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004889
4890 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004891 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004892 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004893 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004894 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004895 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004896 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004897 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004898 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004899 IEEE80211_HW_AP_LINK_PS |
4900 IEEE80211_HW_AMPDU_AGGREGATION |
4901 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004902
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004903 wl->hw->wiphy->cipher_suites = cipher_suites;
4904 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4905
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004906 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004907 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4908 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004909 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004910 wl->hw->wiphy->max_sched_scan_ssids = 16;
4911 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004912 /*
4913 * Maximum length of elements in scanning probe request templates
4914 * should be the maximum length possible for a template, without
4915 * the IEEE80211 header of the template
4916 */
Eliad Peller154037d2011-08-14 13:17:12 +03004917 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004918 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004919
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004920 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4921 sizeof(struct ieee80211_header);
4922
Eliad Peller1ec23f72011-08-25 14:26:54 +03004923 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4924
Luciano Coelho4a31c112011-03-21 23:16:14 +02004925 /* make sure all our channels fit in the scanned_ch bitmask */
4926 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4927 ARRAY_SIZE(wl1271_channels_5ghz) >
4928 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004929 /*
4930 * We keep local copies of the band structs because we need to
4931 * modify them on a per-device basis.
4932 */
4933 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4934 sizeof(wl1271_band_2ghz));
4935 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4936 sizeof(wl1271_band_5ghz));
4937
4938 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4939 &wl->bands[IEEE80211_BAND_2GHZ];
4940 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4941 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004942
Kalle Valo12bd8942010-03-18 12:26:33 +02004943 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004944 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004945
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004946 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4947
Felipe Balbia390e852011-10-06 10:07:44 +03004948 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004949
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004950 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004951 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004952
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004953 wl->hw->max_rx_aggregation_subframes = 8;
4954
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004955 return 0;
4956}
4957
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004958#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004959
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004960static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004961{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004962 struct ieee80211_hw *hw;
4963 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004964 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004965 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004966
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004967 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004968
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004969 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4970 if (!hw) {
4971 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004972 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004973 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004974 }
4975
4976 wl = hw->priv;
4977 memset(wl, 0, sizeof(*wl));
4978
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004979 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02004980 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004981
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004982 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004983
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004984 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004985 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004986 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4987
Ido Yariva6208652011-03-01 15:14:41 +02004988 skb_queue_head_init(&wl->deferred_rx_queue);
4989 skb_queue_head_init(&wl->deferred_tx_queue);
4990
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004991 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02004992 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004993 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4994 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4995 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004996
Eliad Peller92ef8962011-06-07 12:50:46 +03004997 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4998 if (!wl->freezable_wq) {
4999 ret = -ENOMEM;
5000 goto err_hw;
5001 }
5002
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005003 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005004 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005005 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005006 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005007 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005008 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005009 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005010 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005011 wl->ap_ps_map = 0;
5012 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005013 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005014 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005015 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005016 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005017 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005018 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005019 wl->fwlog_size = 0;
5020 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005021
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005022 /* The system link is always allocated */
5023 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5024
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005025 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005026 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005027 wl->tx_frames[i] = NULL;
5028
5029 spin_lock_init(&wl->wl_lock);
5030
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005031 wl->state = WL1271_STATE_OFF;
5032 mutex_init(&wl->mutex);
5033
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005034 /* Apply default driver configuration. */
5035 wl1271_conf_init(wl);
5036
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005037 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5038 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5039 if (!wl->aggr_buf) {
5040 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005041 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005042 }
5043
Ido Yariv990f5de2011-03-31 10:06:59 +02005044 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5045 if (!wl->dummy_packet) {
5046 ret = -ENOMEM;
5047 goto err_aggr;
5048 }
5049
Ido Yariv95dac04f2011-06-06 14:57:06 +03005050 /* Allocate one page for the FW log */
5051 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5052 if (!wl->fwlog) {
5053 ret = -ENOMEM;
5054 goto err_dummy_packet;
5055 }
5056
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005057 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005058
Ido Yariv990f5de2011-03-31 10:06:59 +02005059err_dummy_packet:
5060 dev_kfree_skb(wl->dummy_packet);
5061
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005062err_aggr:
5063 free_pages((unsigned long)wl->aggr_buf, order);
5064
Eliad Peller92ef8962011-06-07 12:50:46 +03005065err_wq:
5066 destroy_workqueue(wl->freezable_wq);
5067
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005068err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005069 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005070 ieee80211_free_hw(hw);
5071
5072err_hw_alloc:
5073
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005074 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005075}
5076
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005077static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005078{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005079 /* Unblock any fwlog readers */
5080 mutex_lock(&wl->mutex);
5081 wl->fwlog_size = -1;
5082 wake_up_interruptible_all(&wl->fwlog_waitq);
5083 mutex_unlock(&wl->mutex);
5084
Felipe Balbif79f8902011-10-06 13:05:25 +03005085 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005086
Felipe Balbif79f8902011-10-06 13:05:25 +03005087 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005088
Felipe Balbif79f8902011-10-06 13:05:25 +03005089 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005090 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005091 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005092 free_pages((unsigned long)wl->aggr_buf,
5093 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005094
5095 wl1271_debugfs_exit(wl);
5096
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005097 vfree(wl->fw);
5098 wl->fw = NULL;
5099 kfree(wl->nvs);
5100 wl->nvs = NULL;
5101
5102 kfree(wl->fw_status);
5103 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005104 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005105
5106 ieee80211_free_hw(wl->hw);
5107
5108 return 0;
5109}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005110
Felipe Balbia390e852011-10-06 10:07:44 +03005111static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5112{
5113 struct wl1271 *wl = cookie;
5114 unsigned long flags;
5115
5116 wl1271_debug(DEBUG_IRQ, "IRQ");
5117
5118 /* complete the ELP completion */
5119 spin_lock_irqsave(&wl->wl_lock, flags);
5120 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5121 if (wl->elp_compl) {
5122 complete(wl->elp_compl);
5123 wl->elp_compl = NULL;
5124 }
5125
5126 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5127 /* don't enqueue a work right now. mark it as pending */
5128 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5129 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5130 disable_irq_nosync(wl->irq);
5131 pm_wakeup_event(wl->dev, 0);
5132 spin_unlock_irqrestore(&wl->wl_lock, flags);
5133 return IRQ_HANDLED;
5134 }
5135 spin_unlock_irqrestore(&wl->wl_lock, flags);
5136
5137 return IRQ_WAKE_THREAD;
5138}
5139
Felipe Balbice2a2172011-10-05 14:12:55 +03005140static int __devinit wl12xx_probe(struct platform_device *pdev)
5141{
Felipe Balbia390e852011-10-06 10:07:44 +03005142 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5143 struct ieee80211_hw *hw;
5144 struct wl1271 *wl;
5145 unsigned long irqflags;
5146 int ret = -ENODEV;
5147
5148 hw = wl1271_alloc_hw();
5149 if (IS_ERR(hw)) {
5150 wl1271_error("can't allocate hw");
5151 ret = PTR_ERR(hw);
5152 goto out;
5153 }
5154
5155 wl = hw->priv;
5156 wl->irq = platform_get_irq(pdev, 0);
5157 wl->ref_clock = pdata->board_ref_clock;
5158 wl->tcxo_clock = pdata->board_tcxo_clock;
5159 wl->platform_quirks = pdata->platform_quirks;
5160 wl->set_power = pdata->set_power;
5161 wl->dev = &pdev->dev;
5162 wl->if_ops = pdata->ops;
5163
5164 platform_set_drvdata(pdev, wl);
5165
5166 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5167 irqflags = IRQF_TRIGGER_RISING;
5168 else
5169 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5170
5171 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5172 irqflags,
5173 pdev->name, wl);
5174 if (ret < 0) {
5175 wl1271_error("request_irq() failed: %d", ret);
5176 goto out_free_hw;
5177 }
5178
5179 ret = enable_irq_wake(wl->irq);
5180 if (!ret) {
5181 wl->irq_wake_enabled = true;
5182 device_init_wakeup(wl->dev, 1);
5183 if (pdata->pwr_in_suspend)
5184 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5185
5186 }
5187 disable_irq(wl->irq);
5188
5189 ret = wl1271_init_ieee80211(wl);
5190 if (ret)
5191 goto out_irq;
5192
5193 ret = wl1271_register_hw(wl);
5194 if (ret)
5195 goto out_irq;
5196
Felipe Balbif79f8902011-10-06 13:05:25 +03005197 /* Create sysfs file to control bt coex state */
5198 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5199 if (ret < 0) {
5200 wl1271_error("failed to create sysfs file bt_coex_state");
5201 goto out_irq;
5202 }
5203
5204 /* Create sysfs file to get HW PG version */
5205 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5206 if (ret < 0) {
5207 wl1271_error("failed to create sysfs file hw_pg_ver");
5208 goto out_bt_coex_state;
5209 }
5210
5211 /* Create sysfs file for the FW log */
5212 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5213 if (ret < 0) {
5214 wl1271_error("failed to create sysfs file fwlog");
5215 goto out_hw_pg_ver;
5216 }
5217
Felipe Balbice2a2172011-10-05 14:12:55 +03005218 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005219
Felipe Balbif79f8902011-10-06 13:05:25 +03005220out_hw_pg_ver:
5221 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5222
5223out_bt_coex_state:
5224 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5225
Felipe Balbia390e852011-10-06 10:07:44 +03005226out_irq:
5227 free_irq(wl->irq, wl);
5228
5229out_free_hw:
5230 wl1271_free_hw(wl);
5231
5232out:
5233 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005234}
5235
5236static int __devexit wl12xx_remove(struct platform_device *pdev)
5237{
Felipe Balbia390e852011-10-06 10:07:44 +03005238 struct wl1271 *wl = platform_get_drvdata(pdev);
5239
5240 if (wl->irq_wake_enabled) {
5241 device_init_wakeup(wl->dev, 0);
5242 disable_irq_wake(wl->irq);
5243 }
5244 wl1271_unregister_hw(wl);
5245 free_irq(wl->irq, wl);
5246 wl1271_free_hw(wl);
5247
Felipe Balbice2a2172011-10-05 14:12:55 +03005248 return 0;
5249}
5250
5251static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005252 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005253 { } /* Terminating Entry */
5254};
5255MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5256
5257static struct platform_driver wl12xx_driver = {
5258 .probe = wl12xx_probe,
5259 .remove = __devexit_p(wl12xx_remove),
5260 .id_table = wl12xx_id_table,
5261 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005262 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005263 .owner = THIS_MODULE,
5264 }
5265};
5266
5267static int __init wl12xx_init(void)
5268{
5269 return platform_driver_register(&wl12xx_driver);
5270}
5271module_init(wl12xx_init);
5272
5273static void __exit wl12xx_exit(void)
5274{
5275 platform_driver_unregister(&wl12xx_driver);
5276}
5277module_exit(wl12xx_exit);
5278
Guy Eilam491bbd62011-01-12 10:33:29 +01005279u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005280EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005281module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005282MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5283
Ido Yariv95dac04f2011-06-06 14:57:06 +03005284module_param_named(fwlog, fwlog_param, charp, 0);
5285MODULE_PARM_DESC(keymap,
5286 "FW logger options: continuous, ondemand, dbgpins or disable");
5287
Eliad Peller2a5bff02011-08-25 18:10:59 +03005288module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5289MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5290
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005291MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005292MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005293MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");