blob: 44d52efedc742e623b9022a103a25e33b03da2e0 [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 Peller536129c82011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Pellerba8447f62011-10-10 10:13:00 +0200461 wl1271_check_operstate(wl, wlvif, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300462
Eliad Pellerba8447f62011-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 Pellerba8447f62011-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 Pellerba8447f62011-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 Yarivbaacb9ae2011-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 Yarivbaacb9ae2011-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 Yarivbaacb9ae2011-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 Pellerba8447f62011-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 Yarivbaacb9ae2011-06-06 14:57:05 +03001250
1251 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1252
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001253 ieee80211_restart_hw(wl->hw);
1254
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001255 /*
1256 * Its safe to enable TX now - the queues are stopped after a request
1257 * to restart the HW.
1258 */
1259 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001260 return;
1261out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001262 mutex_unlock(&wl->mutex);
1263}
1264
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001265static void wl1271_fw_wakeup(struct wl1271 *wl)
1266{
1267 u32 elp_reg;
1268
1269 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001270 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001271}
1272
1273static int wl1271_setup(struct wl1271 *wl)
1274{
1275 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1276 if (!wl->fw_status)
1277 return -ENOMEM;
1278
1279 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1280 if (!wl->tx_res_if) {
1281 kfree(wl->fw_status);
1282 return -ENOMEM;
1283 }
1284
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 return 0;
1286}
1287
1288static int wl1271_chip_wakeup(struct wl1271 *wl)
1289{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001290 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291 int ret = 0;
1292
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001293 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001294 ret = wl1271_power_on(wl);
1295 if (ret < 0)
1296 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001297 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001298 wl1271_io_reset(wl);
1299 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001300
1301 /* We don't need a real memory partition here, because we only want
1302 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001303 memset(&partition, 0, sizeof(partition));
1304 partition.reg.start = REGISTERS_BASE;
1305 partition.reg.size = REGISTERS_DOWN_SIZE;
1306 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001307
1308 /* ELP module wake up */
1309 wl1271_fw_wakeup(wl);
1310
1311 /* whal_FwCtrl_BootSm() */
1312
1313 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001314 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315
1316 /* 1. check if chip id is valid */
1317
1318 switch (wl->chip.id) {
1319 case CHIP_ID_1271_PG10:
1320 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1321 wl->chip.id);
1322
1323 ret = wl1271_setup(wl);
1324 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001325 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001326 break;
1327 case CHIP_ID_1271_PG20:
1328 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1329 wl->chip.id);
1330
1331 ret = wl1271_setup(wl);
1332 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001333 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001334 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001335 case CHIP_ID_1283_PG20:
1336 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1337 wl->chip.id);
1338
1339 ret = wl1271_setup(wl);
1340 if (ret < 0)
1341 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001342
Ido Yariv0da13da2011-03-31 10:06:58 +02001343 if (wl1271_set_block_size(wl))
1344 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001345 break;
1346 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001348 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001349 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001350 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001351 }
1352
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001353 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001354 ret = wl1271_fetch_firmware(wl);
1355 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001356 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357 }
1358
1359 /* No NVS from netlink, try to get it from the filesystem */
1360 if (wl->nvs == NULL) {
1361 ret = wl1271_fetch_nvs(wl);
1362 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001363 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364 }
1365
1366out:
1367 return ret;
1368}
1369
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370int wl1271_plt_start(struct wl1271 *wl)
1371{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001372 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001373 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001374 int ret;
1375
1376 mutex_lock(&wl->mutex);
1377
1378 wl1271_notice("power up");
1379
1380 if (wl->state != WL1271_STATE_OFF) {
1381 wl1271_error("cannot go into PLT state because not "
1382 "in off state: %d", wl->state);
1383 ret = -EBUSY;
1384 goto out;
1385 }
1386
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001387 while (retries) {
1388 retries--;
1389 ret = wl1271_chip_wakeup(wl);
1390 if (ret < 0)
1391 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001392
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001393 ret = wl1271_boot(wl);
1394 if (ret < 0)
1395 goto power_off;
1396
1397 ret = wl1271_plt_init(wl);
1398 if (ret < 0)
1399 goto irq_disable;
1400
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001401 wl->state = WL1271_STATE_PLT;
1402 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001403 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001404
Gery Kahn6f07b722011-07-18 14:21:49 +03001405 /* update hw/fw version info in wiphy struct */
1406 wiphy->hw_version = wl->chip.id;
1407 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1408 sizeof(wiphy->fw_version));
1409
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001410 goto out;
1411
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001412irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001413 mutex_unlock(&wl->mutex);
1414 /* Unlocking the mutex in the middle of handling is
1415 inherently unsafe. In this case we deem it safe to do,
1416 because we need to let any possibly pending IRQ out of
1417 the system (and while we are WL1271_STATE_OFF the IRQ
1418 work function will not do anything.) Also, any other
1419 possible concurrent operations will fail due to the
1420 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001421 wl1271_disable_interrupts(wl);
1422 wl1271_flush_deferred_work(wl);
1423 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001424 mutex_lock(&wl->mutex);
1425power_off:
1426 wl1271_power_off(wl);
1427 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001428
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001429 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1430 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001431out:
1432 mutex_unlock(&wl->mutex);
1433
1434 return ret;
1435}
1436
Luciano Coelho4623ec72011-03-21 19:26:41 +02001437static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438{
1439 int ret = 0;
1440
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441 wl1271_notice("power down");
1442
1443 if (wl->state != WL1271_STATE_PLT) {
1444 wl1271_error("cannot power down because not in PLT "
1445 "state: %d", wl->state);
1446 ret = -EBUSY;
1447 goto out;
1448 }
1449
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001450 wl1271_power_off(wl);
1451
1452 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001453 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001456 wl1271_disable_interrupts(wl);
1457 wl1271_flush_deferred_work(wl);
1458 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001459 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001460 mutex_lock(&wl->mutex);
1461out:
1462 return ret;
1463}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001464
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001465int wl1271_plt_stop(struct wl1271 *wl)
1466{
1467 int ret;
1468
1469 mutex_lock(&wl->mutex);
1470 ret = __wl1271_plt_stop(wl);
1471 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001472 return ret;
1473}
1474
Johannes Berg7bb45682011-02-24 14:42:06 +01001475static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001476{
1477 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001478 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1479 struct ieee80211_vif *vif = info->control.vif;
1480 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
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
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001485 mapping = skb_get_queue_mapping(skb);
1486 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001487
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001488 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001489
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001490 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001491
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001492 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001493 if (hlid == WL12XX_INVALID_LINK_ID ||
1494 !test_bit(hlid, wlvif->links_map)) {
1495 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
1496 dev_kfree_skb(skb);
1497 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001498 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001499
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001500 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1501 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1502
Arik Nemtsov04b4d69c2011-08-14 13:17:39 +03001503 wl->tx_queue_count[q]++;
1504
1505 /*
1506 * The workqueue is slow to process the tx_queue and we need stop
1507 * the queue here, otherwise the queue will get too long.
1508 */
1509 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1510 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1511 ieee80211_stop_queue(wl->hw, mapping);
1512 set_bit(q, &wl->stopped_queues_map);
1513 }
1514
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001515 /*
1516 * The chip specific setup must run before the first TX packet -
1517 * before that, the tx_work will not be initialized!
1518 */
1519
Ido Yarivb07d4032011-03-01 15:14:43 +02001520 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1521 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001522 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001523
Arik Nemtsov04216da2011-08-14 13:17:38 +03001524out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001525 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001526}
1527
Shahar Leviae47c452011-03-06 16:32:14 +02001528int wl1271_tx_dummy_packet(struct wl1271 *wl)
1529{
Ido Yariv990f5de2011-03-31 10:06:59 +02001530 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001531 int q;
1532
1533 /* no need to queue a new dummy packet if one is already pending */
1534 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1535 return 0;
1536
1537 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001538
Ido Yariv990f5de2011-03-31 10:06:59 +02001539 spin_lock_irqsave(&wl->wl_lock, flags);
1540 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001541 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001542 spin_unlock_irqrestore(&wl->wl_lock, flags);
1543
1544 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1545 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001546 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001547
1548 /*
1549 * If the FW TX is busy, TX work will be scheduled by the threaded
1550 * interrupt handler function
1551 */
1552 return 0;
1553}
1554
1555/*
1556 * The size of the dummy packet should be at least 1400 bytes. However, in
1557 * order to minimize the number of bus transactions, aligning it to 512 bytes
1558 * boundaries could be beneficial, performance wise
1559 */
1560#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1561
Luciano Coelhocf27d862011-04-01 21:08:23 +03001562static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001563{
1564 struct sk_buff *skb;
1565 struct ieee80211_hdr_3addr *hdr;
1566 unsigned int dummy_packet_size;
1567
1568 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1569 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1570
1571 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001572 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001573 wl1271_warning("Failed to allocate a dummy packet skb");
1574 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001575 }
1576
1577 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1578
1579 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1580 memset(hdr, 0, sizeof(*hdr));
1581 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001582 IEEE80211_STYPE_NULLFUNC |
1583 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001584
Ido Yariv990f5de2011-03-31 10:06:59 +02001585 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001586
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001587 /* Dummy packets require the TID to be management */
1588 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001589
1590 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001591 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001592 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001593
Ido Yariv990f5de2011-03-31 10:06:59 +02001594 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001595}
1596
Ido Yariv990f5de2011-03-31 10:06:59 +02001597
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001598static struct notifier_block wl1271_dev_notifier = {
1599 .notifier_call = wl1271_dev_notify,
1600};
1601
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001602#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001603static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1604 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001605{
Eliad Pellere85d1622011-06-27 13:06:43 +03001606 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001607
Eliad Peller94390642011-05-13 11:57:13 +03001608 mutex_lock(&wl->mutex);
1609
Eliad Pellerba8447f62011-10-10 10:13:00 +02001610 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001611 goto out_unlock;
1612
Eliad Peller94390642011-05-13 11:57:13 +03001613 ret = wl1271_ps_elp_wakeup(wl);
1614 if (ret < 0)
1615 goto out_unlock;
1616
1617 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001618 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001619 DECLARE_COMPLETION_ONSTACK(compl);
1620
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001621 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001622 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001623 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001624 if (ret < 0)
1625 goto out_sleep;
1626
1627 /* we must unlock here so we will be able to get events */
1628 wl1271_ps_elp_sleep(wl);
1629 mutex_unlock(&wl->mutex);
1630
1631 ret = wait_for_completion_timeout(
1632 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1633 if (ret <= 0) {
1634 wl1271_warning("couldn't enter ps mode!");
1635 ret = -EBUSY;
1636 goto out;
1637 }
1638
1639 /* take mutex again, and wakeup */
1640 mutex_lock(&wl->mutex);
1641
1642 ret = wl1271_ps_elp_wakeup(wl);
1643 if (ret < 0)
1644 goto out_unlock;
1645 }
1646out_sleep:
1647 wl1271_ps_elp_sleep(wl);
1648out_unlock:
1649 mutex_unlock(&wl->mutex);
1650out:
1651 return ret;
1652
1653}
1654
Eliad Peller0603d892011-10-05 11:55:51 +02001655static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1656 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001657{
Eliad Pellere85d1622011-06-27 13:06:43 +03001658 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001659
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001660 mutex_lock(&wl->mutex);
1661
Eliad Peller53d40d02011-10-10 10:13:02 +02001662 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001663 goto out_unlock;
1664
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001665 ret = wl1271_ps_elp_wakeup(wl);
1666 if (ret < 0)
1667 goto out_unlock;
1668
Eliad Peller0603d892011-10-05 11:55:51 +02001669 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001670
1671 wl1271_ps_elp_sleep(wl);
1672out_unlock:
1673 mutex_unlock(&wl->mutex);
1674 return ret;
1675
1676}
1677
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001678static int wl1271_configure_suspend(struct wl1271 *wl,
1679 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001680{
Eliad Peller536129c82011-10-05 11:55:45 +02001681 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001682 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c82011-10-05 11:55:45 +02001683 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001684 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001685 return 0;
1686}
1687
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001688static void wl1271_configure_resume(struct wl1271 *wl,
1689 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001690{
1691 int ret;
Eliad Peller536129c82011-10-05 11:55:45 +02001692 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1693 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001694
1695 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001696 return;
1697
1698 mutex_lock(&wl->mutex);
1699 ret = wl1271_ps_elp_wakeup(wl);
1700 if (ret < 0)
1701 goto out;
1702
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001703 if (is_sta) {
1704 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001705 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001706 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001707 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001708 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001709 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001710 }
Eliad Peller94390642011-05-13 11:57:13 +03001711
1712 wl1271_ps_elp_sleep(wl);
1713out:
1714 mutex_unlock(&wl->mutex);
1715}
1716
Eliad Peller402e48612011-05-13 11:57:09 +03001717static int wl1271_op_suspend(struct ieee80211_hw *hw,
1718 struct cfg80211_wowlan *wow)
1719{
1720 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001721 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001722 int ret;
1723
Eliad Peller402e48612011-05-13 11:57:09 +03001724 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001725 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001726
Eliad Peller4a859df2011-06-06 12:21:52 +03001727 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001728 wl12xx_for_each_wlvif(wl, wlvif) {
1729 ret = wl1271_configure_suspend(wl, wlvif);
1730 if (ret < 0) {
1731 wl1271_warning("couldn't prepare device to suspend");
1732 return ret;
1733 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001734 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001735 /* flush any remaining work */
1736 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001737
1738 /*
1739 * disable and re-enable interrupts in order to flush
1740 * the threaded_irq
1741 */
1742 wl1271_disable_interrupts(wl);
1743
1744 /*
1745 * set suspended flag to avoid triggering a new threaded_irq
1746 * work. no need for spinlock as interrupts are disabled.
1747 */
1748 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1749
1750 wl1271_enable_interrupts(wl);
1751 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001752 wl12xx_for_each_wlvif(wl, wlvif) {
1753 flush_delayed_work(&wlvif->pspoll_work);
1754 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001755 flush_delayed_work(&wl->elp_work);
1756
Eliad Peller402e48612011-05-13 11:57:09 +03001757 return 0;
1758}
1759
1760static int wl1271_op_resume(struct ieee80211_hw *hw)
1761{
1762 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001763 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001764 unsigned long flags;
1765 bool run_irq_work = false;
1766
Eliad Peller402e48612011-05-13 11:57:09 +03001767 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1768 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001769 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001770
1771 /*
1772 * re-enable irq_work enqueuing, and call irq_work directly if
1773 * there is a pending work.
1774 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001775 spin_lock_irqsave(&wl->wl_lock, flags);
1776 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1777 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1778 run_irq_work = true;
1779 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001780
Eliad Peller4a859df2011-06-06 12:21:52 +03001781 if (run_irq_work) {
1782 wl1271_debug(DEBUG_MAC80211,
1783 "run postponed irq_work directly");
1784 wl1271_irq(0, wl);
1785 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001786 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001787 wl12xx_for_each_wlvif(wl, wlvif) {
1788 wl1271_configure_resume(wl, wlvif);
1789 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001790 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001791
Eliad Peller402e48612011-05-13 11:57:09 +03001792 return 0;
1793}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001794#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001795
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001796static int wl1271_op_start(struct ieee80211_hw *hw)
1797{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001798 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1799
1800 /*
1801 * We have to delay the booting of the hardware because
1802 * we need to know the local MAC address before downloading and
1803 * initializing the firmware. The MAC address cannot be changed
1804 * after boot, and without the proper MAC address, the firmware
1805 * will not function properly.
1806 *
1807 * The MAC address is first known when the corresponding interface
1808 * is added. That is where we will initialize the hardware.
1809 */
1810
1811 return 0;
1812}
1813
1814static void wl1271_op_stop(struct ieee80211_hw *hw)
1815{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001816 struct wl1271 *wl = hw->priv;
1817 int i;
1818
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001819 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001820
Eliad Peller10c8cd02011-10-10 10:13:06 +02001821 mutex_lock(&wl->mutex);
1822 if (wl->state == WL1271_STATE_OFF) {
1823 mutex_unlock(&wl->mutex);
1824 return;
1825 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001826 /*
1827 * this must be before the cancel_work calls below, so that the work
1828 * functions don't perform further work.
1829 */
1830 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001831 mutex_unlock(&wl->mutex);
1832
1833 mutex_lock(&wl_list_mutex);
1834 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001835 mutex_unlock(&wl_list_mutex);
1836
1837 wl1271_disable_interrupts(wl);
1838 wl1271_flush_deferred_work(wl);
1839 cancel_delayed_work_sync(&wl->scan_complete_work);
1840 cancel_work_sync(&wl->netstack_work);
1841 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001842 cancel_delayed_work_sync(&wl->elp_work);
1843
1844 /* let's notify MAC80211 about the remaining pending TX frames */
1845 wl12xx_tx_reset(wl, true);
1846 mutex_lock(&wl->mutex);
1847
1848 wl1271_power_off(wl);
1849
1850 wl->band = IEEE80211_BAND_2GHZ;
1851
1852 wl->rx_counter = 0;
1853 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1854 wl->tx_blocks_available = 0;
1855 wl->tx_allocated_blocks = 0;
1856 wl->tx_results_count = 0;
1857 wl->tx_packets_count = 0;
1858 wl->time_offset = 0;
1859 wl->vif = NULL;
1860 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1861 wl->ap_fw_ps_map = 0;
1862 wl->ap_ps_map = 0;
1863 wl->sched_scanning = false;
1864 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1865 memset(wl->links_map, 0, sizeof(wl->links_map));
1866 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1867 wl->active_sta_count = 0;
1868
1869 /* The system link is always allocated */
1870 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1871
1872 /*
1873 * this is performed after the cancel_work calls and the associated
1874 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1875 * get executed before all these vars have been reset.
1876 */
1877 wl->flags = 0;
1878
1879 wl->tx_blocks_freed = 0;
1880
1881 for (i = 0; i < NUM_TX_QUEUES; i++) {
1882 wl->tx_pkts_freed[i] = 0;
1883 wl->tx_allocated_pkts[i] = 0;
1884 }
1885
1886 wl1271_debugfs_reset(wl);
1887
1888 kfree(wl->fw_status);
1889 wl->fw_status = NULL;
1890 kfree(wl->tx_res_if);
1891 wl->tx_res_if = NULL;
1892 kfree(wl->target_mem_map);
1893 wl->target_mem_map = NULL;
1894
1895 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001896}
1897
Eliad Pellere5a359f2011-10-10 10:13:15 +02001898static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1899{
1900 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1901 WL12XX_MAX_RATE_POLICIES);
1902 if (policy >= WL12XX_MAX_RATE_POLICIES)
1903 return -EBUSY;
1904
1905 __set_bit(policy, wl->rate_policies_map);
1906 *idx = policy;
1907 return 0;
1908}
1909
1910static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1911{
1912 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1913 return;
1914
1915 __clear_bit(*idx, wl->rate_policies_map);
1916 *idx = WL12XX_MAX_RATE_POLICIES;
1917}
1918
Eliad Peller536129c82011-10-05 11:55:45 +02001919static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001920{
Eliad Peller536129c82011-10-05 11:55:45 +02001921 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001922 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001923 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001924 return WL1271_ROLE_P2P_GO;
1925 else
1926 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001927
1928 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001929 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001930 return WL1271_ROLE_P2P_CL;
1931 else
1932 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001933
Eliad Peller227e81e2011-08-14 13:17:26 +03001934 case BSS_TYPE_IBSS:
1935 return WL1271_ROLE_IBSS;
1936
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001937 default:
Eliad Peller536129c82011-10-05 11:55:45 +02001938 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001939 }
1940 return WL12XX_INVALID_ROLE_TYPE;
1941}
1942
Eliad Peller83587502011-10-10 10:12:53 +02001943static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001944{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001945 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001946 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001947
Eliad Peller48e93e42011-10-10 10:12:58 +02001948 /* clear everything but the persistent data */
1949 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001950
1951 switch (ieee80211_vif_type_p2p(vif)) {
1952 case NL80211_IFTYPE_P2P_CLIENT:
1953 wlvif->p2p = 1;
1954 /* fall-through */
1955 case NL80211_IFTYPE_STATION:
1956 wlvif->bss_type = BSS_TYPE_STA_BSS;
1957 break;
1958 case NL80211_IFTYPE_ADHOC:
1959 wlvif->bss_type = BSS_TYPE_IBSS;
1960 break;
1961 case NL80211_IFTYPE_P2P_GO:
1962 wlvif->p2p = 1;
1963 /* fall-through */
1964 case NL80211_IFTYPE_AP:
1965 wlvif->bss_type = BSS_TYPE_AP_BSS;
1966 break;
1967 default:
1968 wlvif->bss_type = MAX_BSS_TYPE;
1969 return -EOPNOTSUPP;
1970 }
1971
Eliad Peller0603d892011-10-05 11:55:51 +02001972 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001973 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001974 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001975
Eliad Pellere936bbe2011-10-05 11:55:56 +02001976 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1977 wlvif->bss_type == BSS_TYPE_IBSS) {
1978 /* init sta/ibss data */
1979 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001980 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1981 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1982 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001983 } else {
1984 /* init ap data */
1985 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1986 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001987 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1988 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1989 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1990 wl12xx_allocate_rate_policy(wl,
1991 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001992 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001993
Eliad Peller83587502011-10-10 10:12:53 +02001994 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1995 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001996 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001997 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001998 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001999 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
2000
Eliad Peller1b92f152011-10-10 10:13:09 +02002001 /*
2002 * mac80211 configures some values globally, while we treat them
2003 * per-interface. thus, on init, we have to copy them from wl
2004 */
2005 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02002006 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02002007 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02002008
Eliad Peller9eb599e2011-10-10 10:12:59 +02002009 INIT_WORK(&wlvif->rx_streaming_enable_work,
2010 wl1271_rx_streaming_enable_work);
2011 INIT_WORK(&wlvif->rx_streaming_disable_work,
2012 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02002013 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller876272142011-10-10 10:12:54 +02002014 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02002015
Eliad Peller9eb599e2011-10-10 10:12:59 +02002016 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
2017 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002018 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002019}
2020
Eliad Peller1d095472011-10-10 10:12:49 +02002021static bool wl12xx_init_fw(struct wl1271 *wl)
2022{
2023 int retries = WL1271_BOOT_RETRIES;
2024 bool booted = false;
2025 struct wiphy *wiphy = wl->hw->wiphy;
2026 int ret;
2027
2028 while (retries) {
2029 retries--;
2030 ret = wl1271_chip_wakeup(wl);
2031 if (ret < 0)
2032 goto power_off;
2033
2034 ret = wl1271_boot(wl);
2035 if (ret < 0)
2036 goto power_off;
2037
2038 ret = wl1271_hw_init(wl);
2039 if (ret < 0)
2040 goto irq_disable;
2041
2042 booted = true;
2043 break;
2044
2045irq_disable:
2046 mutex_unlock(&wl->mutex);
2047 /* Unlocking the mutex in the middle of handling is
2048 inherently unsafe. In this case we deem it safe to do,
2049 because we need to let any possibly pending IRQ out of
2050 the system (and while we are WL1271_STATE_OFF the IRQ
2051 work function will not do anything.) Also, any other
2052 possible concurrent operations will fail due to the
2053 current state, hence the wl1271 struct should be safe. */
2054 wl1271_disable_interrupts(wl);
2055 wl1271_flush_deferred_work(wl);
2056 cancel_work_sync(&wl->netstack_work);
2057 mutex_lock(&wl->mutex);
2058power_off:
2059 wl1271_power_off(wl);
2060 }
2061
2062 if (!booted) {
2063 wl1271_error("firmware boot failed despite %d retries",
2064 WL1271_BOOT_RETRIES);
2065 goto out;
2066 }
2067
2068 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2069
2070 /* update hw/fw version info in wiphy struct */
2071 wiphy->hw_version = wl->chip.id;
2072 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2073 sizeof(wiphy->fw_version));
2074
2075 /*
2076 * Now we know if 11a is supported (info from the NVS), so disable
2077 * 11a channels if not supported
2078 */
2079 if (!wl->enable_11a)
2080 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2081
2082 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2083 wl->enable_11a ? "" : "not ");
2084
2085 wl->state = WL1271_STATE_ON;
2086out:
2087 return booted;
2088}
2089
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002090static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2091 struct ieee80211_vif *vif)
2092{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002093 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02002094 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002095 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002096 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002097 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002098
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002099 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002100 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002101
2102 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002103 ret = wl1271_ps_elp_wakeup(wl);
2104 if (ret < 0)
2105 goto out_unlock;
2106
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002107 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002108 wl1271_debug(DEBUG_MAC80211,
2109 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002110 ret = -EBUSY;
2111 goto out;
2112 }
2113
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002114 /*
2115 * in some very corner case HW recovery scenarios its possible to
2116 * get here before __wl1271_op_remove_interface is complete, so
2117 * opt out if that is the case.
2118 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002119 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2120 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002121 ret = -EBUSY;
2122 goto out;
2123 }
2124
Eliad Peller83587502011-10-10 10:12:53 +02002125 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002126 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002127 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002128
Eliad Peller252efa42011-10-05 11:56:00 +02002129 wlvif->wl = wl;
Eliad Peller536129c82011-10-05 11:55:45 +02002130 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002131 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2132 ret = -EINVAL;
2133 goto out;
2134 }
Eliad Peller1d095472011-10-10 10:12:49 +02002135
Eliad Peller784f6942011-10-05 11:55:39 +02002136 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002137 * TODO: after the nvs issue will be solved, move this block
2138 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002139 */
Eliad Peller1d095472011-10-10 10:12:49 +02002140 if (wl->state == WL1271_STATE_OFF) {
2141 /*
2142 * we still need this in order to configure the fw
2143 * while uploading the nvs
2144 */
2145 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002146
Eliad Peller1d095472011-10-10 10:12:49 +02002147 booted = wl12xx_init_fw(wl);
2148 if (!booted) {
2149 ret = -EINVAL;
2150 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002151 }
Eliad Peller1d095472011-10-10 10:12:49 +02002152 }
Eliad Peller04e80792011-08-14 13:17:09 +03002153
Eliad Peller1d095472011-10-10 10:12:49 +02002154 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2155 wlvif->bss_type == BSS_TYPE_IBSS) {
2156 /*
2157 * The device role is a special role used for
2158 * rx and tx frames prior to association (as
2159 * the STA role can get packets only from
2160 * its associated bssid)
2161 */
Eliad Peller784f6942011-10-05 11:55:39 +02002162 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002163 WL1271_ROLE_DEVICE,
2164 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002165 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002166 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002167 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002168
Eliad Peller1d095472011-10-10 10:12:49 +02002169 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2170 role_type, &wlvif->role_id);
2171 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002172 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002173
2174 ret = wl1271_init_vif_specific(wl, vif);
2175 if (ret < 0)
2176 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002177
2178 wl->vif = vif;
Eliad Peller876272142011-10-10 10:12:54 +02002179 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002180 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002181
2182 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2183 wl->ap_count++;
2184 else
2185 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002186out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002187 wl1271_ps_elp_sleep(wl);
2188out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002189 mutex_unlock(&wl->mutex);
2190
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002191 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002192 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002193 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002194 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002195
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002196 return ret;
2197}
2198
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002199static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c82011-10-05 11:55:45 +02002200 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002201 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002202{
Eliad Peller536129c82011-10-05 11:55:45 +02002203 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002204 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002205
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002206 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002207
Eliad Peller10c8cd02011-10-10 10:13:06 +02002208 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2209 return;
2210
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002211 /* because of hardware recovery, we may get here twice */
2212 if (wl->state != WL1271_STATE_ON)
2213 return;
2214
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002215 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002216
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002217 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c82011-10-05 11:55:45 +02002218 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002219 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002220
Eliad Pellerbaf62772011-10-10 10:12:52 +02002221 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2222 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002223 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002224 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002225 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002226 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002227 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002228 }
2229
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002230 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2231 /* disable active roles */
2232 ret = wl1271_ps_elp_wakeup(wl);
2233 if (ret < 0)
2234 goto deinit;
2235
Eliad Peller536129c82011-10-05 11:55:45 +02002236 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002237 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002238 if (ret < 0)
2239 goto deinit;
2240 }
2241
Eliad Peller0603d892011-10-05 11:55:51 +02002242 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002243 if (ret < 0)
2244 goto deinit;
2245
2246 wl1271_ps_elp_sleep(wl);
2247 }
2248deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002249 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002250 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002251
2252 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2253 wlvif->bss_type == BSS_TYPE_IBSS) {
2254 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2255 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2256 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2257 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2258 } else {
2259 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2260 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2261 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2262 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2263 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2264 wl12xx_free_rate_policy(wl,
2265 &wlvif->ap.ucast_rate_idx[i]);
2266 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002267
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002268 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002269 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002270 if (wl->last_wlvif == wlvif)
2271 wl->last_wlvif = NULL;
Eliad Peller876272142011-10-10 10:12:54 +02002272 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002273 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002274 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002275 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03002276
Eliad Pellera4e41302011-10-11 11:49:15 +02002277 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2278 wl->ap_count--;
2279 else
2280 wl->sta_count--;
2281
Eliad Pellerbaf62772011-10-10 10:12:52 +02002282 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002283 del_timer_sync(&wlvif->rx_streaming_timer);
2284 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2285 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002286 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002287
Eliad Pellerbaf62772011-10-10 10:12:52 +02002288 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002289}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002290
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002291static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2292 struct ieee80211_vif *vif)
2293{
2294 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002295 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002296 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002297
2298 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002299
2300 if (wl->state == WL1271_STATE_OFF ||
2301 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2302 goto out;
2303
Juuso Oikarinen67353292010-11-18 15:19:02 +02002304 /*
2305 * wl->vif can be null here if someone shuts down the interface
2306 * just when hardware recovery has been started.
2307 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002308 wl12xx_for_each_wlvif(wl, iter) {
2309 if (iter != wlvif)
2310 continue;
2311
Eliad Peller536129c82011-10-05 11:55:45 +02002312 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002313 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002314 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002315 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002316out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002317 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002318 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002319}
2320
Eliad Peller87fbcb02011-10-05 11:55:41 +02002321static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2322 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002323{
2324 int ret;
Eliad Peller536129c82011-10-05 11:55:45 +02002325 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002326
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002327 /*
2328 * One of the side effects of the JOIN command is that is clears
2329 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2330 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002331 * Currently the only valid scenario for JOIN during association
2332 * is on roaming, in which case we will also be given new keys.
2333 * Keep the below message for now, unless it starts bothering
2334 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002335 */
Eliad Pellerba8447f62011-10-10 10:13:00 +02002336 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002337 wl1271_info("JOIN while associated.");
2338
2339 if (set_assoc)
Eliad Pellerba8447f62011-10-10 10:13:00 +02002340 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002341
Eliad Peller227e81e2011-08-14 13:17:26 +03002342 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002343 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002344 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002345 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002346 if (ret < 0)
2347 goto out;
2348
Eliad Pellerba8447f62011-10-10 10:13:00 +02002349 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002350 goto out;
2351
2352 /*
2353 * The join command disable the keep-alive mode, shut down its process,
2354 * and also clear the template config, so we need to reset it all after
2355 * the join. The acx_aid starts the keep-alive process, and the order
2356 * of the commands below is relevant.
2357 */
Eliad Peller0603d892011-10-05 11:55:51 +02002358 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002359 if (ret < 0)
2360 goto out;
2361
Eliad Peller0603d892011-10-05 11:55:51 +02002362 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002363 if (ret < 0)
2364 goto out;
2365
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002366 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002367 if (ret < 0)
2368 goto out;
2369
Eliad Peller0603d892011-10-05 11:55:51 +02002370 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2371 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002372 ACX_KEEP_ALIVE_TPL_VALID);
2373 if (ret < 0)
2374 goto out;
2375
2376out:
2377 return ret;
2378}
2379
Eliad Peller0603d892011-10-05 11:55:51 +02002380static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002381{
2382 int ret;
2383
Eliad Peller52630c52011-10-10 10:13:08 +02002384 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002385 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2386
Shahar Levi6d158ff2011-09-08 13:01:33 +03002387 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002388 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002389 }
2390
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002391 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002392 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002393 if (ret < 0)
2394 goto out;
2395
Oz Krakowskib992c682011-06-26 10:36:02 +03002396 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002397 wlvif->tx_security_last_seq_lsb = 0;
2398 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002399
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002400out:
2401 return ret;
2402}
2403
Eliad Peller87fbcb02011-10-05 11:55:41 +02002404static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002405{
Eliad Peller1b92f152011-10-10 10:13:09 +02002406 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002407 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002408}
2409
Eliad Peller251c1772011-08-14 13:17:17 +03002410static bool wl12xx_is_roc(struct wl1271 *wl)
2411{
2412 u8 role_id;
2413
2414 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2415 if (role_id >= WL12XX_MAX_ROLES)
2416 return false;
2417
2418 return true;
2419}
2420
Eliad Peller87fbcb02011-10-05 11:55:41 +02002421static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2422 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002423{
2424 int ret;
2425
2426 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002427 /* no need to croc if we weren't busy (e.g. during boot) */
2428 if (wl12xx_is_roc(wl)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002429 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002430 if (ret < 0)
2431 goto out;
2432
Eliad Peller7edebf52011-10-05 11:55:52 +02002433 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002434 if (ret < 0)
2435 goto out;
2436 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002437 wlvif->rate_set =
2438 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2439 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002440 if (ret < 0)
2441 goto out;
2442 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002443 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002444 ACX_KEEP_ALIVE_TPL_INVALID);
2445 if (ret < 0)
2446 goto out;
2447 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2448 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002449 /* The current firmware only supports sched_scan in idle */
2450 if (wl->sched_scanning) {
2451 wl1271_scan_sched_scan_stop(wl);
2452 ieee80211_sched_scan_stopped(wl->hw);
2453 }
2454
Eliad Peller7edebf52011-10-05 11:55:52 +02002455 ret = wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002456 if (ret < 0)
2457 goto out;
2458
Eliad Peller1b92f152011-10-10 10:13:09 +02002459 ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002460 if (ret < 0)
2461 goto out;
2462 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2463 }
2464
2465out:
2466 return ret;
2467}
2468
Eliad Peller9f259c42011-10-10 10:13:12 +02002469static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2470 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002471{
Eliad Peller9f259c42011-10-10 10:13:12 +02002472 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2473 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002474
2475 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2476
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002477 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002478 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002479 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002480 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002481 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002482 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002483 wlvif->band = conf->channel->band;
2484 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002485
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002486 if (!is_ap) {
2487 /*
2488 * FIXME: the mac80211 should really provide a fixed
2489 * rate to use here. for now, just use the smallest
2490 * possible rate for the band as a fixed rate for
2491 * association frames and other control messages.
2492 */
Eliad Pellerba8447f62011-10-10 10:13:00 +02002493 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002494 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002495
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002496 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002497 wl1271_tx_min_rate_get(wl,
2498 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002499 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002500 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002501 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002502 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002503
Eliad Pellerba8447f62011-10-10 10:13:00 +02002504 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2505 &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002506 if (wl12xx_is_roc(wl)) {
2507 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002508 ret = wl12xx_croc(wl,
2509 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002510 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002511 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002512 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002513 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002514 if (ret < 0)
2515 wl1271_warning("cmd join on channel "
2516 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002517 } else {
2518 /*
2519 * change the ROC channel. do it only if we are
2520 * not idle. otherwise, CROC will be called
2521 * anyway.
2522 */
2523 if (wl12xx_is_roc(wl) &&
2524 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002525 ret = wl12xx_croc(wl,
2526 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002527 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002528 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002529
Eliad Peller1b92f152011-10-10 10:13:09 +02002530 ret = wl12xx_roc(wl, wlvif,
Eliad Peller7edebf52011-10-05 11:55:52 +02002531 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002532 if (ret < 0)
2533 wl1271_warning("roc failed %d",
2534 ret);
2535 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002536 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002537 }
2538 }
2539
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002540 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002541 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002542 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002543 if (ret < 0)
2544 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002545 }
2546
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002547 /*
2548 * if mac80211 changes the PSM mode, make sure the mode is not
2549 * incorrectly changed after the pspoll failure active window.
2550 */
2551 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002552 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002553
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002554 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002555 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2556 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002557
2558 /*
2559 * We enter PSM only if we're already associated.
2560 * If we're not, we'll enter it when joining an SSID,
2561 * through the bss_info_changed() hook.
2562 */
Eliad Pellerba8447f62011-10-10 10:13:00 +02002563 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002564 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002565 ret = wl1271_ps_set_mode(wl, wlvif,
2566 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002567 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002568 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002569 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002570 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002571 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002572
Eliad Pellerc29bb002011-10-10 10:13:03 +02002573 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002574
Eliad Pellerc29bb002011-10-10 10:13:03 +02002575 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002576 ret = wl1271_ps_set_mode(wl, wlvif,
2577 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002578 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002579 }
2580
Eliad Peller6bd65022011-10-10 10:13:11 +02002581 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002582 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002583 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002584 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002585
Eliad Peller6bd65022011-10-10 10:13:11 +02002586 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002587 }
2588
Eliad Peller9f259c42011-10-10 10:13:12 +02002589 return 0;
2590}
2591
2592static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2593{
2594 struct wl1271 *wl = hw->priv;
2595 struct wl12xx_vif *wlvif;
2596 struct ieee80211_conf *conf = &hw->conf;
2597 int channel, ret = 0;
2598
2599 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2600
2601 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2602 " changed 0x%x",
2603 channel,
2604 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2605 conf->power_level,
2606 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2607 changed);
2608
2609 /*
2610 * mac80211 will go to idle nearly immediately after transmitting some
2611 * frames, such as the deauth. To make sure those frames reach the air,
2612 * wait here until the TX queue is fully flushed.
2613 */
2614 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2615 (conf->flags & IEEE80211_CONF_IDLE))
2616 wl1271_tx_flush(wl);
2617
2618 mutex_lock(&wl->mutex);
2619
2620 /* we support configuring the channel and band even while off */
2621 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2622 wl->band = conf->channel->band;
2623 wl->channel = channel;
2624 }
2625
2626 if (changed & IEEE80211_CONF_CHANGE_POWER)
2627 wl->power_level = conf->power_level;
2628
2629 if (unlikely(wl->state == WL1271_STATE_OFF))
2630 goto out;
2631
2632 ret = wl1271_ps_elp_wakeup(wl);
2633 if (ret < 0)
2634 goto out;
2635
2636 /* configure each interface */
2637 wl12xx_for_each_wlvif(wl, wlvif) {
2638 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2639 if (ret < 0)
2640 goto out_sleep;
2641 }
2642
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002643out_sleep:
2644 wl1271_ps_elp_sleep(wl);
2645
2646out:
2647 mutex_unlock(&wl->mutex);
2648
2649 return ret;
2650}
2651
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002652struct wl1271_filter_params {
2653 bool enabled;
2654 int mc_list_length;
2655 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2656};
2657
Jiri Pirko22bedad32010-04-01 21:22:57 +00002658static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2659 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002660{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002661 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002662 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002663 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002664
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002665 if (unlikely(wl->state == WL1271_STATE_OFF))
2666 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002667
Juuso Oikarinen74441132009-10-13 12:47:53 +03002668 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002669 if (!fp) {
2670 wl1271_error("Out of memory setting filters.");
2671 return 0;
2672 }
2673
2674 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002675 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002676 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2677 fp->enabled = false;
2678 } else {
2679 fp->enabled = true;
2680 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002681 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002682 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002683 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002684 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002685 }
2686
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002687 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002688}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002689
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002690#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2691 FIF_ALLMULTI | \
2692 FIF_FCSFAIL | \
2693 FIF_BCN_PRBRESP_PROMISC | \
2694 FIF_CONTROL | \
2695 FIF_OTHER_BSS)
2696
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002697static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2698 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002699 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002700{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002701 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002702 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002703 struct wl12xx_vif *wlvif;
Eliad Peller536129c82011-10-05 11:55:45 +02002704
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002705 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002706
Arik Nemtsov7d057862010-10-16 19:25:35 +02002707 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2708 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002709
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002710 mutex_lock(&wl->mutex);
2711
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002712 *total &= WL1271_SUPPORTED_FILTERS;
2713 changed &= WL1271_SUPPORTED_FILTERS;
2714
2715 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002716 goto out;
2717
Ido Yariva6208652011-03-01 15:14:41 +02002718 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002719 if (ret < 0)
2720 goto out;
2721
Eliad Peller6e8cd332011-10-10 10:13:13 +02002722 wl12xx_for_each_wlvif(wl, wlvif) {
2723 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2724 if (*total & FIF_ALLMULTI)
2725 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2726 false,
2727 NULL, 0);
2728 else if (fp)
2729 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2730 fp->enabled,
2731 fp->mc_list,
2732 fp->mc_list_length);
2733 if (ret < 0)
2734 goto out_sleep;
2735 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002736 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002737
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002738 /*
2739 * the fw doesn't provide an api to configure the filters. instead,
2740 * the filters configuration is based on the active roles / ROC
2741 * state.
2742 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002743
2744out_sleep:
2745 wl1271_ps_elp_sleep(wl);
2746
2747out:
2748 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002749 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002750}
2751
Eliad Peller170d0e62011-10-05 11:56:06 +02002752static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2753 u8 id, u8 key_type, u8 key_size,
2754 const u8 *key, u8 hlid, u32 tx_seq_32,
2755 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002756{
2757 struct wl1271_ap_key *ap_key;
2758 int i;
2759
2760 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2761
2762 if (key_size > MAX_KEY_SIZE)
2763 return -EINVAL;
2764
2765 /*
2766 * Find next free entry in ap_keys. Also check we are not replacing
2767 * an existing key.
2768 */
2769 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002770 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002771 break;
2772
Eliad Peller170d0e62011-10-05 11:56:06 +02002773 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002774 wl1271_warning("trying to record key replacement");
2775 return -EINVAL;
2776 }
2777 }
2778
2779 if (i == MAX_NUM_KEYS)
2780 return -EBUSY;
2781
2782 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2783 if (!ap_key)
2784 return -ENOMEM;
2785
2786 ap_key->id = id;
2787 ap_key->key_type = key_type;
2788 ap_key->key_size = key_size;
2789 memcpy(ap_key->key, key, key_size);
2790 ap_key->hlid = hlid;
2791 ap_key->tx_seq_32 = tx_seq_32;
2792 ap_key->tx_seq_16 = tx_seq_16;
2793
Eliad Peller170d0e62011-10-05 11:56:06 +02002794 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002795 return 0;
2796}
2797
Eliad Peller170d0e62011-10-05 11:56:06 +02002798static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002799{
2800 int i;
2801
2802 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002803 kfree(wlvif->ap.recorded_keys[i]);
2804 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002805 }
2806}
2807
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002808static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002809{
2810 int i, ret = 0;
2811 struct wl1271_ap_key *key;
2812 bool wep_key_added = false;
2813
2814 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002815 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002816 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002817 break;
2818
Eliad Peller170d0e62011-10-05 11:56:06 +02002819 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002820 hlid = key->hlid;
2821 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002822 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002823
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002824 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002825 key->id, key->key_type,
2826 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002827 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002828 key->tx_seq_16);
2829 if (ret < 0)
2830 goto out;
2831
2832 if (key->key_type == KEY_WEP)
2833 wep_key_added = true;
2834 }
2835
2836 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002837 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002838 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002839 if (ret < 0)
2840 goto out;
2841 }
2842
2843out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002844 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002845 return ret;
2846}
2847
Eliad Peller536129c82011-10-05 11:55:45 +02002848static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2849 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002850 u8 key_size, const u8 *key, u32 tx_seq_32,
2851 u16 tx_seq_16, struct ieee80211_sta *sta)
2852{
2853 int ret;
Eliad Peller536129c82011-10-05 11:55:45 +02002854 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002855
2856 if (is_ap) {
2857 struct wl1271_station *wl_sta;
2858 u8 hlid;
2859
2860 if (sta) {
2861 wl_sta = (struct wl1271_station *)sta->drv_priv;
2862 hlid = wl_sta->hlid;
2863 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002864 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002865 }
2866
Eliad Peller53d40d02011-10-10 10:13:02 +02002867 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002868 /*
2869 * We do not support removing keys after AP shutdown.
2870 * Pretend we do to make mac80211 happy.
2871 */
2872 if (action != KEY_ADD_OR_REPLACE)
2873 return 0;
2874
Eliad Peller170d0e62011-10-05 11:56:06 +02002875 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002876 key_type, key_size,
2877 key, hlid, tx_seq_32,
2878 tx_seq_16);
2879 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002880 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002881 id, key_type, key_size,
2882 key, hlid, tx_seq_32,
2883 tx_seq_16);
2884 }
2885
2886 if (ret < 0)
2887 return ret;
2888 } else {
2889 const u8 *addr;
2890 static const u8 bcast_addr[ETH_ALEN] = {
2891 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2892 };
2893
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002894 /*
2895 * A STA set to GEM cipher requires 2 tx spare blocks.
2896 * Return to default value when GEM cipher key is removed
2897 */
2898 if (key_type == KEY_GEM) {
2899 if (action == KEY_ADD_OR_REPLACE)
2900 wl->tx_spare_blocks = 2;
2901 else if (action == KEY_REMOVE)
2902 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2903 }
2904
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002905 addr = sta ? sta->addr : bcast_addr;
2906
2907 if (is_zero_ether_addr(addr)) {
2908 /* We dont support TX only encryption */
2909 return -EOPNOTSUPP;
2910 }
2911
2912 /* The wl1271 does not allow to remove unicast keys - they
2913 will be cleared automatically on next CMD_JOIN. Ignore the
2914 request silently, as we dont want the mac80211 to emit
2915 an error message. */
2916 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2917 return 0;
2918
Eliad Peller010d3d32011-08-14 13:17:31 +03002919 /* don't remove key if hlid was already deleted */
2920 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002921 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002922 return 0;
2923
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002924 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002925 id, key_type, key_size,
2926 key, addr, tx_seq_32,
2927 tx_seq_16);
2928 if (ret < 0)
2929 return ret;
2930
2931 /* the default WEP key needs to be configured at least once */
2932 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002933 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002934 wlvif->default_key,
2935 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002936 if (ret < 0)
2937 return ret;
2938 }
2939 }
2940
2941 return 0;
2942}
2943
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002944static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2945 struct ieee80211_vif *vif,
2946 struct ieee80211_sta *sta,
2947 struct ieee80211_key_conf *key_conf)
2948{
2949 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02002950 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002951 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002952 u32 tx_seq_32 = 0;
2953 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002954 u8 key_type;
2955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002956 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2957
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002958 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002959 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002960 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002961 key_conf->keylen, key_conf->flags);
2962 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2963
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002964 mutex_lock(&wl->mutex);
2965
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002966 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2967 ret = -EAGAIN;
2968 goto out_unlock;
2969 }
2970
Ido Yariva6208652011-03-01 15:14:41 +02002971 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002972 if (ret < 0)
2973 goto out_unlock;
2974
Johannes Berg97359d12010-08-10 09:46:38 +02002975 switch (key_conf->cipher) {
2976 case WLAN_CIPHER_SUITE_WEP40:
2977 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002978 key_type = KEY_WEP;
2979
2980 key_conf->hw_key_idx = key_conf->keyidx;
2981 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002982 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002983 key_type = KEY_TKIP;
2984
2985 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002986 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2987 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002988 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002989 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002990 key_type = KEY_AES;
2991
2992 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Eliad Peller48e93e42011-10-10 10:12:58 +02002993 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2994 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002995 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002996 case WL1271_CIPHER_SUITE_GEM:
2997 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002998 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2999 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003000 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003001 default:
Johannes Berg97359d12010-08-10 09:46:38 +02003002 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003003
3004 ret = -EOPNOTSUPP;
3005 goto out_sleep;
3006 }
3007
3008 switch (cmd) {
3009 case SET_KEY:
Eliad Peller536129c82011-10-05 11:55:45 +02003010 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003011 key_conf->keyidx, key_type,
3012 key_conf->keylen, key_conf->key,
3013 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003014 if (ret < 0) {
3015 wl1271_error("Could not add or replace key");
3016 goto out_sleep;
3017 }
3018 break;
3019
3020 case DISABLE_KEY:
Eliad Peller536129c82011-10-05 11:55:45 +02003021 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003022 key_conf->keyidx, key_type,
3023 key_conf->keylen, key_conf->key,
3024 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003025 if (ret < 0) {
3026 wl1271_error("Could not remove key");
3027 goto out_sleep;
3028 }
3029 break;
3030
3031 default:
3032 wl1271_error("Unsupported key cmd 0x%x", cmd);
3033 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003034 break;
3035 }
3036
3037out_sleep:
3038 wl1271_ps_elp_sleep(wl);
3039
3040out_unlock:
3041 mutex_unlock(&wl->mutex);
3042
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003043 return ret;
3044}
3045
3046static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003047 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003048 struct cfg80211_scan_request *req)
3049{
3050 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003051 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3052
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003053 int ret;
3054 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003055 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003056
3057 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3058
3059 if (req->n_ssids) {
3060 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003061 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003062 }
3063
3064 mutex_lock(&wl->mutex);
3065
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003066 if (wl->state == WL1271_STATE_OFF) {
3067 /*
3068 * We cannot return -EBUSY here because cfg80211 will expect
3069 * a call to ieee80211_scan_completed if we do - in this case
3070 * there won't be any call.
3071 */
3072 ret = -EAGAIN;
3073 goto out;
3074 }
3075
Ido Yariva6208652011-03-01 15:14:41 +02003076 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003077 if (ret < 0)
3078 goto out;
3079
Eliad Peller251c1772011-08-14 13:17:17 +03003080 /* cancel ROC before scanning */
3081 if (wl12xx_is_roc(wl)) {
Eliad Pellerba8447f62011-10-10 10:13:00 +02003082 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03003083 /* don't allow scanning right now */
3084 ret = -EBUSY;
3085 goto out_sleep;
3086 }
Eliad Peller7edebf52011-10-05 11:55:52 +02003087 wl12xx_croc(wl, wlvif->dev_role_id);
3088 wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003089 }
3090
Eliad Peller784f6942011-10-05 11:55:39 +02003091 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003092out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003093 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003094out:
3095 mutex_unlock(&wl->mutex);
3096
3097 return ret;
3098}
3099
Eliad Peller73ecce32011-06-27 13:06:45 +03003100static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3101 struct ieee80211_vif *vif)
3102{
3103 struct wl1271 *wl = hw->priv;
3104 int ret;
3105
3106 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3107
3108 mutex_lock(&wl->mutex);
3109
3110 if (wl->state == WL1271_STATE_OFF)
3111 goto out;
3112
3113 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3114 goto out;
3115
3116 ret = wl1271_ps_elp_wakeup(wl);
3117 if (ret < 0)
3118 goto out;
3119
3120 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3121 ret = wl1271_scan_stop(wl);
3122 if (ret < 0)
3123 goto out_sleep;
3124 }
3125 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3126 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003127 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003128 wl->scan.req = NULL;
3129 ieee80211_scan_completed(wl->hw, true);
3130
3131out_sleep:
3132 wl1271_ps_elp_sleep(wl);
3133out:
3134 mutex_unlock(&wl->mutex);
3135
3136 cancel_delayed_work_sync(&wl->scan_complete_work);
3137}
3138
Luciano Coelho33c2c062011-05-10 14:46:02 +03003139static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3140 struct ieee80211_vif *vif,
3141 struct cfg80211_sched_scan_request *req,
3142 struct ieee80211_sched_scan_ies *ies)
3143{
3144 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02003145 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003146 int ret;
3147
3148 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3149
3150 mutex_lock(&wl->mutex);
3151
3152 ret = wl1271_ps_elp_wakeup(wl);
3153 if (ret < 0)
3154 goto out;
3155
Eliad Peller536129c82011-10-05 11:55:45 +02003156 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003157 if (ret < 0)
3158 goto out_sleep;
3159
Eliad Peller536129c82011-10-05 11:55:45 +02003160 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003161 if (ret < 0)
3162 goto out_sleep;
3163
3164 wl->sched_scanning = true;
3165
3166out_sleep:
3167 wl1271_ps_elp_sleep(wl);
3168out:
3169 mutex_unlock(&wl->mutex);
3170 return ret;
3171}
3172
3173static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3174 struct ieee80211_vif *vif)
3175{
3176 struct wl1271 *wl = hw->priv;
3177 int ret;
3178
3179 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3180
3181 mutex_lock(&wl->mutex);
3182
3183 ret = wl1271_ps_elp_wakeup(wl);
3184 if (ret < 0)
3185 goto out;
3186
3187 wl1271_scan_sched_scan_stop(wl);
3188
3189 wl1271_ps_elp_sleep(wl);
3190out:
3191 mutex_unlock(&wl->mutex);
3192}
3193
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003194static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3195{
3196 struct wl1271 *wl = hw->priv;
3197 int ret = 0;
3198
3199 mutex_lock(&wl->mutex);
3200
3201 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3202 ret = -EAGAIN;
3203 goto out;
3204 }
3205
Ido Yariva6208652011-03-01 15:14:41 +02003206 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003207 if (ret < 0)
3208 goto out;
3209
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003210 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003211 if (ret < 0)
3212 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3213
3214 wl1271_ps_elp_sleep(wl);
3215
3216out:
3217 mutex_unlock(&wl->mutex);
3218
3219 return ret;
3220}
3221
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003222static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3223{
3224 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003225 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003226 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003227
3228 mutex_lock(&wl->mutex);
3229
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003230 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3231 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003232 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003233 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003234
Ido Yariva6208652011-03-01 15:14:41 +02003235 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003236 if (ret < 0)
3237 goto out;
3238
Eliad Peller6e8cd332011-10-10 10:13:13 +02003239 wl12xx_for_each_wlvif(wl, wlvif) {
3240 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3241 if (ret < 0)
3242 wl1271_warning("set rts threshold failed: %d", ret);
3243 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003244 wl1271_ps_elp_sleep(wl);
3245
3246out:
3247 mutex_unlock(&wl->mutex);
3248
3249 return ret;
3250}
3251
Eliad Peller1fe9f162011-10-05 11:55:48 +02003252static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003253 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003254{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003255 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003256 u8 ssid_len;
3257 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3258 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003259
Eliad Peller889cb362011-05-01 09:56:45 +03003260 if (!ptr) {
3261 wl1271_error("No SSID in IEs!");
3262 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003263 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003264
Eliad Peller889cb362011-05-01 09:56:45 +03003265 ssid_len = ptr[1];
3266 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3267 wl1271_error("SSID is too long!");
3268 return -EINVAL;
3269 }
3270
Eliad Peller1fe9f162011-10-05 11:55:48 +02003271 wlvif->ssid_len = ssid_len;
3272 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003273 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003274}
3275
Eliad Pellerd48055d2011-09-15 12:07:04 +03003276static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3277{
3278 int len;
3279 const u8 *next, *end = skb->data + skb->len;
3280 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3281 skb->len - ieoffset);
3282 if (!ie)
3283 return;
3284 len = ie[1] + 2;
3285 next = ie + len;
3286 memmove(ie, next, end - next);
3287 skb_trim(skb, skb->len - len);
3288}
3289
Eliad Peller26b4bf22011-09-15 12:07:05 +03003290static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3291 unsigned int oui, u8 oui_type,
3292 int ieoffset)
3293{
3294 int len;
3295 const u8 *next, *end = skb->data + skb->len;
3296 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3297 skb->data + ieoffset,
3298 skb->len - ieoffset);
3299 if (!ie)
3300 return;
3301 len = ie[1] + 2;
3302 next = ie + len;
3303 memmove(ie, next, end - next);
3304 skb_trim(skb, skb->len - len);
3305}
3306
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003307static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
Eliad Peller1fe9f162011-10-05 11:55:48 +02003308 struct ieee80211_vif *vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003309 u8 *probe_rsp_data,
3310 size_t probe_rsp_len,
3311 u32 rates)
3312{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003313 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3314 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003315 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3316 int ssid_ie_offset, ie_offset, templ_len;
3317 const u8 *ptr;
3318
3319 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003320 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003321 return wl1271_cmd_template_set(wl,
3322 CMD_TEMPL_AP_PROBE_RESPONSE,
3323 probe_rsp_data,
3324 probe_rsp_len, 0,
3325 rates);
3326
3327 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3328 wl1271_error("probe_rsp template too big");
3329 return -EINVAL;
3330 }
3331
3332 /* start searching from IE offset */
3333 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3334
3335 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3336 probe_rsp_len - ie_offset);
3337 if (!ptr) {
3338 wl1271_error("No SSID in beacon!");
3339 return -EINVAL;
3340 }
3341
3342 ssid_ie_offset = ptr - probe_rsp_data;
3343 ptr += (ptr[1] + 2);
3344
3345 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3346
3347 /* insert SSID from bss_conf */
3348 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3349 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3350 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3351 bss_conf->ssid, bss_conf->ssid_len);
3352 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3353
3354 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3355 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3356 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3357
3358 return wl1271_cmd_template_set(wl,
3359 CMD_TEMPL_AP_PROBE_RESPONSE,
3360 probe_rsp_templ,
3361 templ_len, 0,
3362 rates);
3363}
3364
Arik Nemtsove78a2872010-10-16 19:07:21 +02003365static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003366 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003367 struct ieee80211_bss_conf *bss_conf,
3368 u32 changed)
3369{
Eliad Peller0603d892011-10-05 11:55:51 +02003370 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003371 int ret = 0;
3372
3373 if (changed & BSS_CHANGED_ERP_SLOT) {
3374 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003375 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003376 else
Eliad Peller0603d892011-10-05 11:55:51 +02003377 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003378 if (ret < 0) {
3379 wl1271_warning("Set slot time failed %d", ret);
3380 goto out;
3381 }
3382 }
3383
3384 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3385 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003386 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003387 else
Eliad Peller0603d892011-10-05 11:55:51 +02003388 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003389 }
3390
3391 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3392 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003393 ret = wl1271_acx_cts_protect(wl, wlvif,
3394 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003395 else
Eliad Peller0603d892011-10-05 11:55:51 +02003396 ret = wl1271_acx_cts_protect(wl, wlvif,
3397 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003398 if (ret < 0) {
3399 wl1271_warning("Set ctsprotect failed %d", ret);
3400 goto out;
3401 }
3402 }
3403
3404out:
3405 return ret;
3406}
3407
3408static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3409 struct ieee80211_vif *vif,
3410 struct ieee80211_bss_conf *bss_conf,
3411 u32 changed)
3412{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003413 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c82011-10-05 11:55:45 +02003414 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003415 int ret = 0;
3416
3417 if ((changed & BSS_CHANGED_BEACON_INT)) {
3418 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3419 bss_conf->beacon_int);
3420
Eliad Peller6a899792011-10-05 11:55:58 +02003421 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003422 }
3423
3424 if ((changed & BSS_CHANGED_BEACON)) {
3425 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003426 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003427 int ieoffset = offsetof(struct ieee80211_mgmt,
3428 u.beacon.variable);
3429 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3430 u16 tmpl_id;
3431
3432 if (!beacon)
3433 goto out;
3434
3435 wl1271_debug(DEBUG_MASTER, "beacon updated");
3436
Eliad Peller1fe9f162011-10-05 11:55:48 +02003437 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003438 if (ret < 0) {
3439 dev_kfree_skb(beacon);
3440 goto out;
3441 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003442 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003443 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3444 CMD_TEMPL_BEACON;
3445 ret = wl1271_cmd_template_set(wl, tmpl_id,
3446 beacon->data,
3447 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003448 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003449 if (ret < 0) {
3450 dev_kfree_skb(beacon);
3451 goto out;
3452 }
3453
Eliad Pellerd48055d2011-09-15 12:07:04 +03003454 /* remove TIM ie from probe response */
3455 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3456
Eliad Peller26b4bf22011-09-15 12:07:05 +03003457 /*
3458 * remove p2p ie from probe response.
3459 * the fw reponds to probe requests that don't include
3460 * the p2p ie. probe requests with p2p ie will be passed,
3461 * and will be responded by the supplicant (the spec
3462 * forbids including the p2p ie when responding to probe
3463 * requests that didn't include it).
3464 */
3465 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3466 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3467
Arik Nemtsove78a2872010-10-16 19:07:21 +02003468 hdr = (struct ieee80211_hdr *) beacon->data;
3469 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3470 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003471 if (is_ap)
Eliad Peller1fe9f162011-10-05 11:55:48 +02003472 ret = wl1271_ap_set_probe_resp_tmpl(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003473 beacon->data,
3474 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003475 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003476 else
3477 ret = wl1271_cmd_template_set(wl,
3478 CMD_TEMPL_PROBE_RESPONSE,
3479 beacon->data,
3480 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003481 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003482 dev_kfree_skb(beacon);
3483 if (ret < 0)
3484 goto out;
3485 }
3486
3487out:
3488 return ret;
3489}
3490
3491/* AP mode changes */
3492static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003493 struct ieee80211_vif *vif,
3494 struct ieee80211_bss_conf *bss_conf,
3495 u32 changed)
3496{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003497 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003498 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003499
Arik Nemtsove78a2872010-10-16 19:07:21 +02003500 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3501 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003502
Eliad Peller87fbcb02011-10-05 11:55:41 +02003503 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003504 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003505 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003506 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003507
Eliad Peller87fbcb02011-10-05 11:55:41 +02003508 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003509 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003510 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003511 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003512 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003513
Eliad Peller784f6942011-10-05 11:55:39 +02003514 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003515 if (ret < 0)
3516 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003517 }
3518
Arik Nemtsove78a2872010-10-16 19:07:21 +02003519 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3520 if (ret < 0)
3521 goto out;
3522
3523 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3524 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003525 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003526 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003527 if (ret < 0)
3528 goto out;
3529
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003530 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003531 if (ret < 0)
3532 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003533
Eliad Peller53d40d02011-10-10 10:13:02 +02003534 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003535 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003536 }
3537 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003538 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003539 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003540 if (ret < 0)
3541 goto out;
3542
Eliad Peller53d40d02011-10-10 10:13:02 +02003543 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003544 wl1271_debug(DEBUG_AP, "stopped AP");
3545 }
3546 }
3547 }
3548
Eliad Peller0603d892011-10-05 11:55:51 +02003549 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003550 if (ret < 0)
3551 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003552
3553 /* Handle HT information change */
3554 if ((changed & BSS_CHANGED_HT) &&
3555 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003556 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003557 bss_conf->ht_operation_mode);
3558 if (ret < 0) {
3559 wl1271_warning("Set ht information failed %d", ret);
3560 goto out;
3561 }
3562 }
3563
Arik Nemtsove78a2872010-10-16 19:07:21 +02003564out:
3565 return;
3566}
3567
3568/* STA/IBSS mode changes */
3569static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3570 struct ieee80211_vif *vif,
3571 struct ieee80211_bss_conf *bss_conf,
3572 u32 changed)
3573{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003574 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003575 bool do_join = false, set_assoc = false;
Eliad Peller536129c82011-10-05 11:55:45 +02003576 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003577 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003578 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003579 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003580 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003581 bool sta_exists = false;
3582 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003583
3584 if (is_ibss) {
3585 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3586 changed);
3587 if (ret < 0)
3588 goto out;
3589 }
3590
Eliad Peller227e81e2011-08-14 13:17:26 +03003591 if (changed & BSS_CHANGED_IBSS) {
3592 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003593 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003594 ibss_joined = true;
3595 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003596 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3597 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003598 wl1271_unjoin(wl, wlvif);
Eliad Peller7edebf52011-10-05 11:55:52 +02003599 wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller1b92f152011-10-10 10:13:09 +02003600 wl12xx_roc(wl, wlvif, wlvif->dev_role_id);
Eliad Peller227e81e2011-08-14 13:17:26 +03003601 }
3602 }
3603 }
3604
3605 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003606 do_join = true;
3607
3608 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003609 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003610 do_join = true;
3611
Eliad Peller227e81e2011-08-14 13:17:26 +03003612 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003613 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3614 bss_conf->enable_beacon ? "enabled" : "disabled");
3615
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003616 do_join = true;
3617 }
3618
Arik Nemtsove78a2872010-10-16 19:07:21 +02003619 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003620 bool enable = false;
3621 if (bss_conf->cqm_rssi_thold)
3622 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003623 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003624 bss_conf->cqm_rssi_thold,
3625 bss_conf->cqm_rssi_hyst);
3626 if (ret < 0)
3627 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003628 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003629 }
3630
Eliad Pellercdf09492011-10-05 11:55:44 +02003631 if (changed & BSS_CHANGED_BSSID)
3632 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003633 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003634 if (ret < 0)
3635 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003636
Eliad Peller784f6942011-10-05 11:55:39 +02003637 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003638 if (ret < 0)
3639 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003640
Eliad Pellerfa287b82010-12-26 09:27:50 +01003641 /* Need to update the BSSID (for filtering etc) */
3642 do_join = true;
3643 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003644
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003645 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3646 rcu_read_lock();
3647 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3648 if (!sta)
3649 goto sta_not_found;
3650
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003651 /* save the supp_rates of the ap */
3652 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3653 if (sta->ht_cap.ht_supported)
3654 sta_rate_set |=
3655 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003656 sta_ht_cap = sta->ht_cap;
3657 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003658
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003659sta_not_found:
3660 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003661 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003662
Arik Nemtsove78a2872010-10-16 19:07:21 +02003663 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003664 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003665 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003666 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003667 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003668 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003669
Eliad Peller74ec8392011-10-05 11:56:02 +02003670 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003671
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003672 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003673 * use basic rates from AP, and determine lowest rate
3674 * to use with control frames.
3675 */
3676 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003677 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003678 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003679 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003680 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003681 wl1271_tx_min_rate_get(wl,
3682 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003683 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003684 wlvif->rate_set =
3685 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003686 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003687 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003688 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003689 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003690 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003691
3692 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003693 * with wl1271, we don't need to update the
3694 * beacon_int and dtim_period, because the firmware
3695 * updates it by itself when the first beacon is
3696 * received after a join.
3697 */
Eliad Peller6840e372011-10-05 11:55:50 +02003698 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003699 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003700 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003701
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003702 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003703 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003704 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003705 dev_kfree_skb(wlvif->probereq);
3706 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003707 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003708 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003709 ieoffset = offsetof(struct ieee80211_mgmt,
3710 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003711 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003712
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003713 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003714 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003715 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003716 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003717 } else {
3718 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003719 bool was_assoc =
Eliad Pellerba8447f62011-10-10 10:13:00 +02003720 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3721 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003722 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003723 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3724 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003725 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003726
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003727 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003728 dev_kfree_skb(wlvif->probereq);
3729 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003730
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003731 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003732 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003733
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003734 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003735 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003736 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003737 wl1271_tx_min_rate_get(wl,
3738 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003739 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003740 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003741 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003742
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003743 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003744 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003745
3746 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003747 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003748 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003749 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003750
3751 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003752 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003753 u32 conf_flags = wl->hw->conf.flags;
3754 /*
3755 * we might have to disable roc, if there was
3756 * no IF_OPER_UP notification.
3757 */
3758 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003759 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003760 if (ret < 0)
3761 goto out;
3762 }
3763 /*
3764 * (we also need to disable roc in case of
3765 * roaming on the same channel. until we will
3766 * have a better flow...)
3767 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003768 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3769 ret = wl12xx_croc(wl,
3770 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003771 if (ret < 0)
3772 goto out;
3773 }
3774
Eliad Peller0603d892011-10-05 11:55:51 +02003775 wl1271_unjoin(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003776 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02003777 wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller1b92f152011-10-10 10:13:09 +02003778 wl12xx_roc(wl, wlvif,
3779 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003780 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003781 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003782 }
3783 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003784
Eliad Pellerd192d262011-05-24 14:33:08 +03003785 if (changed & BSS_CHANGED_IBSS) {
3786 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3787 bss_conf->ibss_joined);
3788
3789 if (bss_conf->ibss_joined) {
3790 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003791 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003792 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003793 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003794 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003795 wl1271_tx_min_rate_get(wl,
3796 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003797
Shahar Levi06b660e2011-09-05 13:54:36 +03003798 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003799 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3800 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003801 if (ret < 0)
3802 goto out;
3803 }
3804 }
3805
Eliad Peller0603d892011-10-05 11:55:51 +02003806 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003807 if (ret < 0)
3808 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003809
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003810 if (changed & BSS_CHANGED_ARP_FILTER) {
3811 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c82011-10-05 11:55:45 +02003812 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003813
Eliad Pellerc5312772010-12-09 11:31:27 +02003814 if (bss_conf->arp_addr_cnt == 1 &&
3815 bss_conf->arp_filter_enabled) {
3816 /*
3817 * The template should have been configured only upon
3818 * association. however, it seems that the correct ip
3819 * isn't being set (when sending), so we have to
3820 * reconfigure the template upon every ip change.
3821 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003822 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003823 if (ret < 0) {
3824 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003825 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003826 }
3827
Eliad Peller0603d892011-10-05 11:55:51 +02003828 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003829 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003830 addr);
3831 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003832 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003833
3834 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003835 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003836 }
3837
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003838 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003839 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003840 if (ret < 0) {
3841 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003842 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003843 }
Eliad Peller251c1772011-08-14 13:17:17 +03003844
3845 /* ROC until connected (after EAPOL exchange) */
3846 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003847 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003848 if (ret < 0)
3849 goto out;
3850
Eliad Pellerba8447f62011-10-10 10:13:00 +02003851 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003852 ieee80211_get_operstate(vif));
3853 }
3854 /*
3855 * stop device role if started (we might already be in
3856 * STA role). TODO: make it better.
3857 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003858 if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3859 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003860 if (ret < 0)
3861 goto out;
3862
Eliad Peller7edebf52011-10-05 11:55:52 +02003863 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003864 if (ret < 0)
3865 goto out;
3866 }
Eliad Peller05dba352011-08-23 16:37:01 +03003867
3868 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003869 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3870 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003871 enum wl1271_cmd_ps_mode mode;
3872
3873 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003874 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003875 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003876 true);
3877 if (ret < 0)
3878 goto out;
3879 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003880 }
3881
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003882 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003883 if (sta_exists) {
3884 if ((changed & BSS_CHANGED_HT) &&
3885 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003886 ret = wl1271_acx_set_ht_capabilities(wl,
3887 &sta_ht_cap,
3888 true,
Eliad Peller154da672011-10-05 11:55:53 +02003889 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003890 if (ret < 0) {
3891 wl1271_warning("Set ht cap true failed %d",
3892 ret);
3893 goto out;
3894 }
3895 }
3896 /* handle new association without HT and disassociation */
3897 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003898 ret = wl1271_acx_set_ht_capabilities(wl,
3899 &sta_ht_cap,
3900 false,
Eliad Peller154da672011-10-05 11:55:53 +02003901 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003902 if (ret < 0) {
3903 wl1271_warning("Set ht cap false failed %d",
3904 ret);
3905 goto out;
3906 }
3907 }
3908 }
3909
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003910 /* Handle HT information change. Done after join. */
3911 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003912 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003913 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003914 bss_conf->ht_operation_mode);
3915 if (ret < 0) {
3916 wl1271_warning("Set ht information failed %d", ret);
3917 goto out;
3918 }
3919 }
3920
Arik Nemtsove78a2872010-10-16 19:07:21 +02003921out:
3922 return;
3923}
3924
3925static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3926 struct ieee80211_vif *vif,
3927 struct ieee80211_bss_conf *bss_conf,
3928 u32 changed)
3929{
3930 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02003931 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3932 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003933 int ret;
3934
3935 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3936 (int)changed);
3937
3938 mutex_lock(&wl->mutex);
3939
3940 if (unlikely(wl->state == WL1271_STATE_OFF))
3941 goto out;
3942
Eliad Peller10c8cd02011-10-10 10:13:06 +02003943 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3944 goto out;
3945
Ido Yariva6208652011-03-01 15:14:41 +02003946 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003947 if (ret < 0)
3948 goto out;
3949
3950 if (is_ap)
3951 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3952 else
3953 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3954
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003955 wl1271_ps_elp_sleep(wl);
3956
3957out:
3958 mutex_unlock(&wl->mutex);
3959}
3960
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003961static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3962 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003963 const struct ieee80211_tx_queue_params *params)
3964{
3965 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003966 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003967 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003968 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003969
3970 mutex_lock(&wl->mutex);
3971
3972 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3973
Kalle Valo4695dc92010-03-18 12:26:38 +02003974 if (params->uapsd)
3975 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3976 else
3977 ps_scheme = CONF_PS_SCHEME_LEGACY;
3978
Arik Nemtsov488fc542010-10-16 20:33:45 +02003979 if (wl->state == WL1271_STATE_OFF) {
3980 /*
3981 * If the state is off, the parameters will be recorded and
3982 * configured on init. This happens in AP-mode.
3983 */
3984 struct conf_tx_ac_category *conf_ac =
3985 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3986 struct conf_tx_tid *conf_tid =
3987 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3988
3989 conf_ac->ac = wl1271_tx_get_queue(queue);
3990 conf_ac->cw_min = (u8)params->cw_min;
3991 conf_ac->cw_max = params->cw_max;
3992 conf_ac->aifsn = params->aifs;
3993 conf_ac->tx_op_limit = params->txop << 5;
3994
3995 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3996 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3997 conf_tid->tsid = wl1271_tx_get_queue(queue);
3998 conf_tid->ps_scheme = ps_scheme;
3999 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
4000 conf_tid->apsd_conf[0] = 0;
4001 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004002 goto out;
4003 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02004004
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004005 ret = wl1271_ps_elp_wakeup(wl);
4006 if (ret < 0)
4007 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004008
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004009 /*
4010 * the txop is confed in units of 32us by the mac80211,
4011 * we need us
4012 */
Eliad Peller0603d892011-10-05 11:55:51 +02004013 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004014 params->cw_min, params->cw_max,
4015 params->aifs, params->txop << 5);
4016 if (ret < 0)
4017 goto out_sleep;
4018
Eliad Peller0603d892011-10-05 11:55:51 +02004019 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004020 CONF_CHANNEL_TYPE_EDCF,
4021 wl1271_tx_get_queue(queue),
4022 ps_scheme, CONF_ACK_POLICY_LEGACY,
4023 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004024
4025out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004026 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004027
4028out:
4029 mutex_unlock(&wl->mutex);
4030
4031 return ret;
4032}
4033
Eliad Peller37a41b42011-09-21 14:06:11 +03004034static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4035 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004036{
4037
4038 struct wl1271 *wl = hw->priv;
4039 u64 mactime = ULLONG_MAX;
4040 int ret;
4041
4042 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4043
4044 mutex_lock(&wl->mutex);
4045
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004046 if (unlikely(wl->state == WL1271_STATE_OFF))
4047 goto out;
4048
Ido Yariva6208652011-03-01 15:14:41 +02004049 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004050 if (ret < 0)
4051 goto out;
4052
4053 ret = wl1271_acx_tsf_info(wl, &mactime);
4054 if (ret < 0)
4055 goto out_sleep;
4056
4057out_sleep:
4058 wl1271_ps_elp_sleep(wl);
4059
4060out:
4061 mutex_unlock(&wl->mutex);
4062 return mactime;
4063}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004064
John W. Linvilleece550d2010-07-28 16:41:06 -04004065static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4066 struct survey_info *survey)
4067{
4068 struct wl1271 *wl = hw->priv;
4069 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004070
John W. Linvilleece550d2010-07-28 16:41:06 -04004071 if (idx != 0)
4072 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004073
John W. Linvilleece550d2010-07-28 16:41:06 -04004074 survey->channel = conf->channel;
4075 survey->filled = SURVEY_INFO_NOISE_DBM;
4076 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004077
John W. Linvilleece550d2010-07-28 16:41:06 -04004078 return 0;
4079}
4080
Arik Nemtsov409622e2011-02-23 00:22:29 +02004081static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004082 struct wl12xx_vif *wlvif,
4083 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004084{
4085 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004086 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004087
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004088
4089 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004090 wl1271_warning("could not allocate HLID - too much stations");
4091 return -EBUSY;
4092 }
4093
4094 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004095 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4096 if (ret < 0) {
4097 wl1271_warning("could not allocate HLID - too many links");
4098 return -EBUSY;
4099 }
4100
4101 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004102 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004103 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004104 return 0;
4105}
4106
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004107void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004108{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004109 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004110 return;
4111
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004112 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004113 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004114 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004115 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004116 __clear_bit(hlid, &wl->ap_ps_map);
4117 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004118 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004119 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004120}
4121
4122static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4123 struct ieee80211_vif *vif,
4124 struct ieee80211_sta *sta)
4125{
4126 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004127 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004128 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004129 int ret = 0;
4130 u8 hlid;
4131
4132 mutex_lock(&wl->mutex);
4133
4134 if (unlikely(wl->state == WL1271_STATE_OFF))
4135 goto out;
4136
Eliad Peller536129c82011-10-05 11:55:45 +02004137 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004138 goto out;
4139
4140 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4141
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004142 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004143 if (ret < 0)
4144 goto out;
4145
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004146 wl_sta = (struct wl1271_station *)sta->drv_priv;
4147 hlid = wl_sta->hlid;
4148
Ido Yariva6208652011-03-01 15:14:41 +02004149 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004150 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004151 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004152
Eliad Peller1b92f152011-10-10 10:13:09 +02004153 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004154 if (ret < 0)
4155 goto out_sleep;
4156
Eliad Pellerb67476e2011-08-14 13:17:23 +03004157 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4158 if (ret < 0)
4159 goto out_sleep;
4160
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004161 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4162 if (ret < 0)
4163 goto out_sleep;
4164
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004165out_sleep:
4166 wl1271_ps_elp_sleep(wl);
4167
Arik Nemtsov409622e2011-02-23 00:22:29 +02004168out_free_sta:
4169 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004170 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004171
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004172out:
4173 mutex_unlock(&wl->mutex);
4174 return ret;
4175}
4176
4177static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4178 struct ieee80211_vif *vif,
4179 struct ieee80211_sta *sta)
4180{
4181 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004182 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004183 struct wl1271_station *wl_sta;
4184 int ret = 0, id;
4185
4186 mutex_lock(&wl->mutex);
4187
4188 if (unlikely(wl->state == WL1271_STATE_OFF))
4189 goto out;
4190
Eliad Peller536129c82011-10-05 11:55:45 +02004191 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004192 goto out;
4193
4194 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4195
4196 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004197 id = wl_sta->hlid;
4198 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004199 goto out;
4200
Ido Yariva6208652011-03-01 15:14:41 +02004201 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004202 if (ret < 0)
4203 goto out;
4204
Eliad Pellerc690ec82011-08-14 13:17:07 +03004205 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004206 if (ret < 0)
4207 goto out_sleep;
4208
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004209 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004210
4211out_sleep:
4212 wl1271_ps_elp_sleep(wl);
4213
4214out:
4215 mutex_unlock(&wl->mutex);
4216 return ret;
4217}
4218
Luciano Coelho4623ec72011-03-21 19:26:41 +02004219static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4220 struct ieee80211_vif *vif,
4221 enum ieee80211_ampdu_mlme_action action,
4222 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4223 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004224{
4225 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004226 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004227 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004228 u8 hlid, *ba_bitmap;
4229
4230 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4231 tid);
4232
4233 /* sanity check - the fields in FW are only 8bits wide */
4234 if (WARN_ON(tid > 0xFF))
4235 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004236
4237 mutex_lock(&wl->mutex);
4238
4239 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4240 ret = -EAGAIN;
4241 goto out;
4242 }
4243
Eliad Peller536129c82011-10-05 11:55:45 +02004244 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004245 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004246 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c82011-10-05 11:55:45 +02004247 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004248 struct wl1271_station *wl_sta;
4249
4250 wl_sta = (struct wl1271_station *)sta->drv_priv;
4251 hlid = wl_sta->hlid;
4252 ba_bitmap = &wl->links[hlid].ba_bitmap;
4253 } else {
4254 ret = -EINVAL;
4255 goto out;
4256 }
4257
Ido Yariva6208652011-03-01 15:14:41 +02004258 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004259 if (ret < 0)
4260 goto out;
4261
Shahar Levi70559a02011-05-22 16:10:22 +03004262 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4263 tid, action);
4264
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004265 switch (action) {
4266 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004267 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004268 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004269 break;
4270 }
4271
4272 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4273 ret = -EBUSY;
4274 wl1271_error("exceeded max RX BA sessions");
4275 break;
4276 }
4277
4278 if (*ba_bitmap & BIT(tid)) {
4279 ret = -EINVAL;
4280 wl1271_error("cannot enable RX BA session on active "
4281 "tid: %d", tid);
4282 break;
4283 }
4284
4285 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4286 hlid);
4287 if (!ret) {
4288 *ba_bitmap |= BIT(tid);
4289 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004290 }
4291 break;
4292
4293 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004294 if (!(*ba_bitmap & BIT(tid))) {
4295 ret = -EINVAL;
4296 wl1271_error("no active RX BA session on tid: %d",
4297 tid);
4298 break;
4299 }
4300
4301 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4302 hlid);
4303 if (!ret) {
4304 *ba_bitmap &= ~BIT(tid);
4305 wl->ba_rx_session_count--;
4306 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004307 break;
4308
4309 /*
4310 * The BA initiator session management in FW independently.
4311 * Falling break here on purpose for all TX APDU commands.
4312 */
4313 case IEEE80211_AMPDU_TX_START:
4314 case IEEE80211_AMPDU_TX_STOP:
4315 case IEEE80211_AMPDU_TX_OPERATIONAL:
4316 ret = -EINVAL;
4317 break;
4318
4319 default:
4320 wl1271_error("Incorrect ampdu action id=%x\n", action);
4321 ret = -EINVAL;
4322 }
4323
4324 wl1271_ps_elp_sleep(wl);
4325
4326out:
4327 mutex_unlock(&wl->mutex);
4328
4329 return ret;
4330}
4331
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004332static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4333 struct ieee80211_vif *vif,
4334 const struct cfg80211_bitrate_mask *mask)
4335{
Eliad Peller83587502011-10-10 10:12:53 +02004336 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004337 struct wl1271 *wl = hw->priv;
4338 int i;
4339
4340 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4341 mask->control[NL80211_BAND_2GHZ].legacy,
4342 mask->control[NL80211_BAND_5GHZ].legacy);
4343
4344 mutex_lock(&wl->mutex);
4345
4346 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004347 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004348 wl1271_tx_enabled_rates_get(wl,
4349 mask->control[i].legacy,
4350 i);
4351 mutex_unlock(&wl->mutex);
4352
4353 return 0;
4354}
4355
Shahar Levi6d158ff2011-09-08 13:01:33 +03004356static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4357 struct ieee80211_channel_switch *ch_switch)
4358{
4359 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004360 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004361 int ret;
4362
4363 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4364
4365 mutex_lock(&wl->mutex);
4366
4367 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004368 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4369 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4370 ieee80211_chswitch_done(vif, false);
4371 }
4372 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004373 }
4374
4375 ret = wl1271_ps_elp_wakeup(wl);
4376 if (ret < 0)
4377 goto out;
4378
Eliad Peller52630c52011-10-10 10:13:08 +02004379 /* TODO: change mac80211 to pass vif as param */
4380 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4381 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004382
Eliad Peller52630c52011-10-10 10:13:08 +02004383 if (!ret)
4384 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4385 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004386
4387 wl1271_ps_elp_sleep(wl);
4388
4389out:
4390 mutex_unlock(&wl->mutex);
4391}
4392
Arik Nemtsov33437892011-04-26 23:35:39 +03004393static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4394{
4395 struct wl1271 *wl = hw->priv;
4396 bool ret = false;
4397
4398 mutex_lock(&wl->mutex);
4399
4400 if (unlikely(wl->state == WL1271_STATE_OFF))
4401 goto out;
4402
4403 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004404 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004405out:
4406 mutex_unlock(&wl->mutex);
4407
4408 return ret;
4409}
4410
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004411/* can't be const, mac80211 writes to this */
4412static struct ieee80211_rate wl1271_rates[] = {
4413 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004414 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4415 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004416 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004417 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4418 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004419 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4420 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004421 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4422 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004423 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4424 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004425 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4426 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004427 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4428 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004429 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4430 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004431 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004432 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4433 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004434 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004435 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4436 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004437 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004438 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4439 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004440 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004441 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4442 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004443 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004444 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4445 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004446 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004447 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4448 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004449 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004450 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4451 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004452};
4453
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004454/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004455static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004456 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004457 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004458 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4459 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4460 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004461 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004462 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4463 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4464 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004465 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004466 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4467 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4468 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004469 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004470};
4471
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004472/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004473static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004474 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004475 7, /* CONF_HW_RXTX_RATE_MCS7 */
4476 6, /* CONF_HW_RXTX_RATE_MCS6 */
4477 5, /* CONF_HW_RXTX_RATE_MCS5 */
4478 4, /* CONF_HW_RXTX_RATE_MCS4 */
4479 3, /* CONF_HW_RXTX_RATE_MCS3 */
4480 2, /* CONF_HW_RXTX_RATE_MCS2 */
4481 1, /* CONF_HW_RXTX_RATE_MCS1 */
4482 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004483
4484 11, /* CONF_HW_RXTX_RATE_54 */
4485 10, /* CONF_HW_RXTX_RATE_48 */
4486 9, /* CONF_HW_RXTX_RATE_36 */
4487 8, /* CONF_HW_RXTX_RATE_24 */
4488
4489 /* TI-specific rate */
4490 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4491
4492 7, /* CONF_HW_RXTX_RATE_18 */
4493 6, /* CONF_HW_RXTX_RATE_12 */
4494 3, /* CONF_HW_RXTX_RATE_11 */
4495 5, /* CONF_HW_RXTX_RATE_9 */
4496 4, /* CONF_HW_RXTX_RATE_6 */
4497 2, /* CONF_HW_RXTX_RATE_5_5 */
4498 1, /* CONF_HW_RXTX_RATE_2 */
4499 0 /* CONF_HW_RXTX_RATE_1 */
4500};
4501
Shahar Levie8b03a22010-10-13 16:09:39 +02004502/* 11n STA capabilities */
4503#define HW_RX_HIGHEST_RATE 72
4504
Shahar Levi00d20102010-11-08 11:20:10 +00004505#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004506 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4507 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004508 .ht_supported = true, \
4509 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4510 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4511 .mcs = { \
4512 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4513 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4514 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4515 }, \
4516}
4517
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004518/* can't be const, mac80211 writes to this */
4519static struct ieee80211_supported_band wl1271_band_2ghz = {
4520 .channels = wl1271_channels,
4521 .n_channels = ARRAY_SIZE(wl1271_channels),
4522 .bitrates = wl1271_rates,
4523 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004524 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004525};
4526
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004527/* 5 GHz data rates for WL1273 */
4528static struct ieee80211_rate wl1271_rates_5ghz[] = {
4529 { .bitrate = 60,
4530 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4531 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4532 { .bitrate = 90,
4533 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4534 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4535 { .bitrate = 120,
4536 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4537 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4538 { .bitrate = 180,
4539 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4540 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4541 { .bitrate = 240,
4542 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4543 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4544 { .bitrate = 360,
4545 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4546 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4547 { .bitrate = 480,
4548 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4549 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4550 { .bitrate = 540,
4551 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4552 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4553};
4554
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004555/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004556static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004557 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4558 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4559 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4560 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4561 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4562 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4563 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4564 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4565 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4566 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4567 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4568 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4569 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4570 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4571 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4572 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4573 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4574 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4575 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4576 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4577 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4578 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4579 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4580 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4581 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4582 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4583 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4584 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4585 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4586 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4587 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4588 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4589 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4590 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004591};
4592
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004593/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004594static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004595 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004596 7, /* CONF_HW_RXTX_RATE_MCS7 */
4597 6, /* CONF_HW_RXTX_RATE_MCS6 */
4598 5, /* CONF_HW_RXTX_RATE_MCS5 */
4599 4, /* CONF_HW_RXTX_RATE_MCS4 */
4600 3, /* CONF_HW_RXTX_RATE_MCS3 */
4601 2, /* CONF_HW_RXTX_RATE_MCS2 */
4602 1, /* CONF_HW_RXTX_RATE_MCS1 */
4603 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004604
4605 7, /* CONF_HW_RXTX_RATE_54 */
4606 6, /* CONF_HW_RXTX_RATE_48 */
4607 5, /* CONF_HW_RXTX_RATE_36 */
4608 4, /* CONF_HW_RXTX_RATE_24 */
4609
4610 /* TI-specific rate */
4611 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4612
4613 3, /* CONF_HW_RXTX_RATE_18 */
4614 2, /* CONF_HW_RXTX_RATE_12 */
4615 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4616 1, /* CONF_HW_RXTX_RATE_9 */
4617 0, /* CONF_HW_RXTX_RATE_6 */
4618 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4619 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4620 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4621};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004622
4623static struct ieee80211_supported_band wl1271_band_5ghz = {
4624 .channels = wl1271_channels_5ghz,
4625 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4626 .bitrates = wl1271_rates_5ghz,
4627 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004628 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004629};
4630
Tobias Klausera0ea9492010-05-20 10:38:11 +02004631static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004632 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4633 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4634};
4635
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004636static const struct ieee80211_ops wl1271_ops = {
4637 .start = wl1271_op_start,
4638 .stop = wl1271_op_stop,
4639 .add_interface = wl1271_op_add_interface,
4640 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004641#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004642 .suspend = wl1271_op_suspend,
4643 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004644#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004645 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004646 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004647 .configure_filter = wl1271_op_configure_filter,
4648 .tx = wl1271_op_tx,
4649 .set_key = wl1271_op_set_key,
4650 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004651 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004652 .sched_scan_start = wl1271_op_sched_scan_start,
4653 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004654 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004655 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004656 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004657 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004658 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004659 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004660 .sta_add = wl1271_op_sta_add,
4661 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004662 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004663 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004664 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004665 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004666 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004667};
4668
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004669
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004670u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004671{
4672 u8 idx;
4673
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004674 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004675
4676 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4677 wl1271_error("Illegal RX rate from HW: %d", rate);
4678 return 0;
4679 }
4680
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004681 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004682 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4683 wl1271_error("Unsupported RX rate from HW: %d", rate);
4684 return 0;
4685 }
4686
4687 return idx;
4688}
4689
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004690static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4691 struct device_attribute *attr,
4692 char *buf)
4693{
4694 struct wl1271 *wl = dev_get_drvdata(dev);
4695 ssize_t len;
4696
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004697 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004698
4699 mutex_lock(&wl->mutex);
4700 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4701 wl->sg_enabled);
4702 mutex_unlock(&wl->mutex);
4703
4704 return len;
4705
4706}
4707
4708static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4709 struct device_attribute *attr,
4710 const char *buf, size_t count)
4711{
4712 struct wl1271 *wl = dev_get_drvdata(dev);
4713 unsigned long res;
4714 int ret;
4715
Luciano Coelho6277ed62011-04-01 17:49:54 +03004716 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004717 if (ret < 0) {
4718 wl1271_warning("incorrect value written to bt_coex_mode");
4719 return count;
4720 }
4721
4722 mutex_lock(&wl->mutex);
4723
4724 res = !!res;
4725
4726 if (res == wl->sg_enabled)
4727 goto out;
4728
4729 wl->sg_enabled = res;
4730
4731 if (wl->state == WL1271_STATE_OFF)
4732 goto out;
4733
Ido Yariva6208652011-03-01 15:14:41 +02004734 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004735 if (ret < 0)
4736 goto out;
4737
4738 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4739 wl1271_ps_elp_sleep(wl);
4740
4741 out:
4742 mutex_unlock(&wl->mutex);
4743 return count;
4744}
4745
4746static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4747 wl1271_sysfs_show_bt_coex_state,
4748 wl1271_sysfs_store_bt_coex_state);
4749
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004750static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4751 struct device_attribute *attr,
4752 char *buf)
4753{
4754 struct wl1271 *wl = dev_get_drvdata(dev);
4755 ssize_t len;
4756
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004757 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004758
4759 mutex_lock(&wl->mutex);
4760 if (wl->hw_pg_ver >= 0)
4761 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4762 else
4763 len = snprintf(buf, len, "n/a\n");
4764 mutex_unlock(&wl->mutex);
4765
4766 return len;
4767}
4768
Gery Kahn6f07b722011-07-18 14:21:49 +03004769static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004770 wl1271_sysfs_show_hw_pg_ver, NULL);
4771
Ido Yariv95dac04f2011-06-06 14:57:06 +03004772static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4773 struct bin_attribute *bin_attr,
4774 char *buffer, loff_t pos, size_t count)
4775{
4776 struct device *dev = container_of(kobj, struct device, kobj);
4777 struct wl1271 *wl = dev_get_drvdata(dev);
4778 ssize_t len;
4779 int ret;
4780
4781 ret = mutex_lock_interruptible(&wl->mutex);
4782 if (ret < 0)
4783 return -ERESTARTSYS;
4784
4785 /* Let only one thread read the log at a time, blocking others */
4786 while (wl->fwlog_size == 0) {
4787 DEFINE_WAIT(wait);
4788
4789 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4790 &wait,
4791 TASK_INTERRUPTIBLE);
4792
4793 if (wl->fwlog_size != 0) {
4794 finish_wait(&wl->fwlog_waitq, &wait);
4795 break;
4796 }
4797
4798 mutex_unlock(&wl->mutex);
4799
4800 schedule();
4801 finish_wait(&wl->fwlog_waitq, &wait);
4802
4803 if (signal_pending(current))
4804 return -ERESTARTSYS;
4805
4806 ret = mutex_lock_interruptible(&wl->mutex);
4807 if (ret < 0)
4808 return -ERESTARTSYS;
4809 }
4810
4811 /* Check if the fwlog is still valid */
4812 if (wl->fwlog_size < 0) {
4813 mutex_unlock(&wl->mutex);
4814 return 0;
4815 }
4816
4817 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4818 len = min(count, (size_t)wl->fwlog_size);
4819 wl->fwlog_size -= len;
4820 memcpy(buffer, wl->fwlog, len);
4821
4822 /* Make room for new messages */
4823 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4824
4825 mutex_unlock(&wl->mutex);
4826
4827 return len;
4828}
4829
4830static struct bin_attribute fwlog_attr = {
4831 .attr = {.name = "fwlog", .mode = S_IRUSR},
4832 .read = wl1271_sysfs_read_fwlog,
4833};
4834
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004835static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004836{
4837 int ret;
4838
4839 if (wl->mac80211_registered)
4840 return 0;
4841
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004842 ret = wl1271_fetch_nvs(wl);
4843 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004844 /* NOTE: The wl->nvs->nvs element must be first, in
4845 * order to simplify the casting, we assume it is at
4846 * the beginning of the wl->nvs structure.
4847 */
4848 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004849
4850 wl->mac_addr[0] = nvs_ptr[11];
4851 wl->mac_addr[1] = nvs_ptr[10];
4852 wl->mac_addr[2] = nvs_ptr[6];
4853 wl->mac_addr[3] = nvs_ptr[5];
4854 wl->mac_addr[4] = nvs_ptr[4];
4855 wl->mac_addr[5] = nvs_ptr[3];
4856 }
4857
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004858 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4859
4860 ret = ieee80211_register_hw(wl->hw);
4861 if (ret < 0) {
4862 wl1271_error("unable to register mac80211 hw: %d", ret);
4863 return ret;
4864 }
4865
4866 wl->mac80211_registered = true;
4867
Eliad Pellerd60080a2010-11-24 12:53:16 +02004868 wl1271_debugfs_init(wl);
4869
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004870 register_netdevice_notifier(&wl1271_dev_notifier);
4871
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004872 wl1271_notice("loaded");
4873
4874 return 0;
4875}
4876
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004877static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004878{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004879 if (wl->state == WL1271_STATE_PLT)
4880 __wl1271_plt_stop(wl);
4881
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004882 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004883 ieee80211_unregister_hw(wl->hw);
4884 wl->mac80211_registered = false;
4885
4886}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004887
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004888static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004889{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004890 static const u32 cipher_suites[] = {
4891 WLAN_CIPHER_SUITE_WEP40,
4892 WLAN_CIPHER_SUITE_WEP104,
4893 WLAN_CIPHER_SUITE_TKIP,
4894 WLAN_CIPHER_SUITE_CCMP,
4895 WL1271_CIPHER_SUITE_GEM,
4896 };
4897
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004898 /* The tx descriptor buffer and the TKIP space. */
4899 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4900 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004901
4902 /* unit us */
4903 /* FIXME: find a proper value */
4904 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004905 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004906
4907 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004908 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004909 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004910 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004911 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004912 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004913 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004914 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004915 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004916 IEEE80211_HW_AP_LINK_PS |
4917 IEEE80211_HW_AMPDU_AGGREGATION |
4918 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004919
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004920 wl->hw->wiphy->cipher_suites = cipher_suites;
4921 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4922
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004923 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004924 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4925 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004926 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004927 wl->hw->wiphy->max_sched_scan_ssids = 16;
4928 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004929 /*
4930 * Maximum length of elements in scanning probe request templates
4931 * should be the maximum length possible for a template, without
4932 * the IEEE80211 header of the template
4933 */
Eliad Peller154037d2011-08-14 13:17:12 +03004934 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004935 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004936
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004937 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4938 sizeof(struct ieee80211_header);
4939
Eliad Peller1ec23f72011-08-25 14:26:54 +03004940 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4941
Luciano Coelho4a31c112011-03-21 23:16:14 +02004942 /* make sure all our channels fit in the scanned_ch bitmask */
4943 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4944 ARRAY_SIZE(wl1271_channels_5ghz) >
4945 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004946 /*
4947 * We keep local copies of the band structs because we need to
4948 * modify them on a per-device basis.
4949 */
4950 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4951 sizeof(wl1271_band_2ghz));
4952 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4953 sizeof(wl1271_band_5ghz));
4954
4955 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4956 &wl->bands[IEEE80211_BAND_2GHZ];
4957 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4958 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004959
Kalle Valo12bd8942010-03-18 12:26:33 +02004960 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004961 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004962
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004963 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4964
Felipe Balbia390e852011-10-06 10:07:44 +03004965 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004966
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004967 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004968 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004969
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004970 wl->hw->max_rx_aggregation_subframes = 8;
4971
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004972 return 0;
4973}
4974
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004975#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004976
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004977static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004978{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004979 struct ieee80211_hw *hw;
4980 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004981 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004982 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004983
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004984 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004985
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004986 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4987 if (!hw) {
4988 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004989 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004990 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004991 }
4992
4993 wl = hw->priv;
4994 memset(wl, 0, sizeof(*wl));
4995
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004996 INIT_LIST_HEAD(&wl->list);
Eliad Peller876272142011-10-10 10:12:54 +02004997 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004998
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004999 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005000
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005001 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005002 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005003 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5004
Ido Yariva6208652011-03-01 15:14:41 +02005005 skb_queue_head_init(&wl->deferred_rx_queue);
5006 skb_queue_head_init(&wl->deferred_tx_queue);
5007
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005008 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005009 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005010 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5011 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5012 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005013
Eliad Peller92ef8962011-06-07 12:50:46 +03005014 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5015 if (!wl->freezable_wq) {
5016 ret = -ENOMEM;
5017 goto err_hw;
5018 }
5019
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005020 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005021 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005022 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005023 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005024 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005025 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005026 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005027 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005028 wl->ap_ps_map = 0;
5029 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005030 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005031 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005032 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005033 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005034 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005035 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005036 wl->fwlog_size = 0;
5037 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005038
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005039 /* The system link is always allocated */
5040 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5041
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005042 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005043 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005044 wl->tx_frames[i] = NULL;
5045
5046 spin_lock_init(&wl->wl_lock);
5047
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005048 wl->state = WL1271_STATE_OFF;
5049 mutex_init(&wl->mutex);
5050
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005051 /* Apply default driver configuration. */
5052 wl1271_conf_init(wl);
5053
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005054 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5055 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5056 if (!wl->aggr_buf) {
5057 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005058 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005059 }
5060
Ido Yariv990f5de2011-03-31 10:06:59 +02005061 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5062 if (!wl->dummy_packet) {
5063 ret = -ENOMEM;
5064 goto err_aggr;
5065 }
5066
Ido Yariv95dac04f2011-06-06 14:57:06 +03005067 /* Allocate one page for the FW log */
5068 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5069 if (!wl->fwlog) {
5070 ret = -ENOMEM;
5071 goto err_dummy_packet;
5072 }
5073
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005074 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005075
Ido Yariv990f5de2011-03-31 10:06:59 +02005076err_dummy_packet:
5077 dev_kfree_skb(wl->dummy_packet);
5078
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005079err_aggr:
5080 free_pages((unsigned long)wl->aggr_buf, order);
5081
Eliad Peller92ef8962011-06-07 12:50:46 +03005082err_wq:
5083 destroy_workqueue(wl->freezable_wq);
5084
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005085err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005086 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005087 ieee80211_free_hw(hw);
5088
5089err_hw_alloc:
5090
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005091 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005092}
5093
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005094static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005095{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005096 /* Unblock any fwlog readers */
5097 mutex_lock(&wl->mutex);
5098 wl->fwlog_size = -1;
5099 wake_up_interruptible_all(&wl->fwlog_waitq);
5100 mutex_unlock(&wl->mutex);
5101
Felipe Balbif79f8902011-10-06 13:05:25 +03005102 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005103
Felipe Balbif79f8902011-10-06 13:05:25 +03005104 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005105
Felipe Balbif79f8902011-10-06 13:05:25 +03005106 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005107 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005108 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005109 free_pages((unsigned long)wl->aggr_buf,
5110 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005111
5112 wl1271_debugfs_exit(wl);
5113
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005114 vfree(wl->fw);
5115 wl->fw = NULL;
5116 kfree(wl->nvs);
5117 wl->nvs = NULL;
5118
5119 kfree(wl->fw_status);
5120 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005121 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005122
5123 ieee80211_free_hw(wl->hw);
5124
5125 return 0;
5126}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005127
Felipe Balbia390e852011-10-06 10:07:44 +03005128static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5129{
5130 struct wl1271 *wl = cookie;
5131 unsigned long flags;
5132
5133 wl1271_debug(DEBUG_IRQ, "IRQ");
5134
5135 /* complete the ELP completion */
5136 spin_lock_irqsave(&wl->wl_lock, flags);
5137 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5138 if (wl->elp_compl) {
5139 complete(wl->elp_compl);
5140 wl->elp_compl = NULL;
5141 }
5142
5143 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5144 /* don't enqueue a work right now. mark it as pending */
5145 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5146 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5147 disable_irq_nosync(wl->irq);
5148 pm_wakeup_event(wl->dev, 0);
5149 spin_unlock_irqrestore(&wl->wl_lock, flags);
5150 return IRQ_HANDLED;
5151 }
5152 spin_unlock_irqrestore(&wl->wl_lock, flags);
5153
5154 return IRQ_WAKE_THREAD;
5155}
5156
Felipe Balbice2a2172011-10-05 14:12:55 +03005157static int __devinit wl12xx_probe(struct platform_device *pdev)
5158{
Felipe Balbia390e852011-10-06 10:07:44 +03005159 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5160 struct ieee80211_hw *hw;
5161 struct wl1271 *wl;
5162 unsigned long irqflags;
5163 int ret = -ENODEV;
5164
5165 hw = wl1271_alloc_hw();
5166 if (IS_ERR(hw)) {
5167 wl1271_error("can't allocate hw");
5168 ret = PTR_ERR(hw);
5169 goto out;
5170 }
5171
5172 wl = hw->priv;
5173 wl->irq = platform_get_irq(pdev, 0);
5174 wl->ref_clock = pdata->board_ref_clock;
5175 wl->tcxo_clock = pdata->board_tcxo_clock;
5176 wl->platform_quirks = pdata->platform_quirks;
5177 wl->set_power = pdata->set_power;
5178 wl->dev = &pdev->dev;
5179 wl->if_ops = pdata->ops;
5180
5181 platform_set_drvdata(pdev, wl);
5182
5183 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5184 irqflags = IRQF_TRIGGER_RISING;
5185 else
5186 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5187
5188 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5189 irqflags,
5190 pdev->name, wl);
5191 if (ret < 0) {
5192 wl1271_error("request_irq() failed: %d", ret);
5193 goto out_free_hw;
5194 }
5195
5196 ret = enable_irq_wake(wl->irq);
5197 if (!ret) {
5198 wl->irq_wake_enabled = true;
5199 device_init_wakeup(wl->dev, 1);
5200 if (pdata->pwr_in_suspend)
5201 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5202
5203 }
5204 disable_irq(wl->irq);
5205
5206 ret = wl1271_init_ieee80211(wl);
5207 if (ret)
5208 goto out_irq;
5209
5210 ret = wl1271_register_hw(wl);
5211 if (ret)
5212 goto out_irq;
5213
Felipe Balbif79f8902011-10-06 13:05:25 +03005214 /* Create sysfs file to control bt coex state */
5215 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5216 if (ret < 0) {
5217 wl1271_error("failed to create sysfs file bt_coex_state");
5218 goto out_irq;
5219 }
5220
5221 /* Create sysfs file to get HW PG version */
5222 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5223 if (ret < 0) {
5224 wl1271_error("failed to create sysfs file hw_pg_ver");
5225 goto out_bt_coex_state;
5226 }
5227
5228 /* Create sysfs file for the FW log */
5229 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5230 if (ret < 0) {
5231 wl1271_error("failed to create sysfs file fwlog");
5232 goto out_hw_pg_ver;
5233 }
5234
Felipe Balbice2a2172011-10-05 14:12:55 +03005235 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005236
Felipe Balbif79f8902011-10-06 13:05:25 +03005237out_hw_pg_ver:
5238 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5239
5240out_bt_coex_state:
5241 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5242
Felipe Balbia390e852011-10-06 10:07:44 +03005243out_irq:
5244 free_irq(wl->irq, wl);
5245
5246out_free_hw:
5247 wl1271_free_hw(wl);
5248
5249out:
5250 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005251}
5252
5253static int __devexit wl12xx_remove(struct platform_device *pdev)
5254{
Felipe Balbia390e852011-10-06 10:07:44 +03005255 struct wl1271 *wl = platform_get_drvdata(pdev);
5256
5257 if (wl->irq_wake_enabled) {
5258 device_init_wakeup(wl->dev, 0);
5259 disable_irq_wake(wl->irq);
5260 }
5261 wl1271_unregister_hw(wl);
5262 free_irq(wl->irq, wl);
5263 wl1271_free_hw(wl);
5264
Felipe Balbice2a2172011-10-05 14:12:55 +03005265 return 0;
5266}
5267
5268static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
5269 { "wl12xx-sdio", 0 },
5270 { "wl12xx-spi", 0 },
5271 { } /* Terminating Entry */
5272};
5273MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5274
5275static struct platform_driver wl12xx_driver = {
5276 .probe = wl12xx_probe,
5277 .remove = __devexit_p(wl12xx_remove),
5278 .id_table = wl12xx_id_table,
5279 .driver = {
5280 .name = "wl12xx",
5281 .owner = THIS_MODULE,
5282 }
5283};
5284
5285static int __init wl12xx_init(void)
5286{
5287 return platform_driver_register(&wl12xx_driver);
5288}
5289module_init(wl12xx_init);
5290
5291static void __exit wl12xx_exit(void)
5292{
5293 platform_driver_unregister(&wl12xx_driver);
5294}
5295module_exit(wl12xx_exit);
5296
Guy Eilam491bbd62011-01-12 10:33:29 +01005297u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005298EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005299module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005300MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5301
Ido Yariv95dac04f2011-06-06 14:57:06 +03005302module_param_named(fwlog, fwlog_param, charp, 0);
5303MODULE_PARM_DESC(keymap,
5304 "FW logger options: continuous, ondemand, dbgpins or disable");
5305
Eliad Peller2a5bff02011-08-25 18:10:59 +03005306module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5307MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5308
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005309MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005310MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005311MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");