blob: afc5381f2870b5660400c014350066d4e1bdf35c [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Felipe Balbia390e852011-10-06 10:07:44 +030035#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "wl12xx.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030038#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030039#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000040#include "reg.h"
41#include "io.h"
42#include "event.h"
43#include "tx.h"
44#include "rx.h"
45#include "ps.h"
46#include "init.h"
47#include "debugfs.h"
48#include "cmd.h"
49#include "boot.h"
50#include "testmode.h"
51#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030052
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020053#define WL1271_BOOT_RETRIES 3
54
Juuso Oikarinen8a080482009-10-13 12:47:44 +030055static struct conf_drv_settings default_conf = {
56 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030057 .params = {
58 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
61 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
62 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
64 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
65 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
66 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
68 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
69 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
70 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
71 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
73 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
74 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
75 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
76 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
77 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
78 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
79 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
82 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
83 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
84 /* active scan params */
85 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
86 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
87 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
88 /* passive scan params */
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
91 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
92 /* passive scan in dual antenna params */
93 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
94 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
95 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
96 /* general params */
97 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
98 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
99 [CONF_SG_BEACON_MISS_PERCENT] = 60,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_RXT] = 1200,
102 [CONF_SG_TXT] = 1000,
103 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
104 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
105 [CONF_SG_HV3_MAX_SERVED] = 6,
106 [CONF_SG_PS_POLL_TIMEOUT] = 10,
107 [CONF_SG_UPSD_TIMEOUT] = 10,
108 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
109 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
110 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
111 /* AP params */
112 [CONF_AP_BEACON_MISS_TX] = 3,
113 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
114 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
115 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
116 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
117 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300118 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200119 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300120 },
121 .rx = {
122 .rx_msdu_life_time = 512000,
123 .packet_detection_threshold = 0,
124 .ps_poll_timeout = 15,
125 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300126 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200127 .rx_cca_threshold = 0,
128 .irq_blk_threshold = 0xFFFF,
129 .irq_pkt_threshold = 0,
130 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300131 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
132 },
133 .tx = {
134 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200135 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300136 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300137 .short_retry_limit = 10,
138 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200139 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300140 },
141 .ac_conf_count = 4,
142 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200143 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300144 .ac = CONF_TX_AC_BE,
145 .cw_min = 15,
146 .cw_max = 63,
147 .aifsn = 3,
148 .tx_op_limit = 0,
149 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200150 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300151 .ac = CONF_TX_AC_BK,
152 .cw_min = 15,
153 .cw_max = 63,
154 .aifsn = 7,
155 .tx_op_limit = 0,
156 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200157 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300158 .ac = CONF_TX_AC_VI,
159 .cw_min = 15,
160 .cw_max = 63,
161 .aifsn = CONF_TX_AIFS_PIFS,
162 .tx_op_limit = 3008,
163 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200164 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300165 .ac = CONF_TX_AC_VO,
166 .cw_min = 15,
167 .cw_max = 63,
168 .aifsn = CONF_TX_AIFS_PIFS,
169 .tx_op_limit = 1504,
170 },
171 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300172 .max_tx_retries = 100,
173 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300175 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200176 [CONF_TX_AC_BE] = {
177 .queue_id = CONF_TX_AC_BE,
178 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300179 .tsid = CONF_TX_AC_BE,
180 .ps_scheme = CONF_PS_SCHEME_LEGACY,
181 .ack_policy = CONF_ACK_POLICY_LEGACY,
182 .apsd_conf = {0, 0},
183 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200184 [CONF_TX_AC_BK] = {
185 .queue_id = CONF_TX_AC_BK,
186 .channel_type = CONF_CHANNEL_TYPE_EDCF,
187 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300188 .ps_scheme = CONF_PS_SCHEME_LEGACY,
189 .ack_policy = CONF_ACK_POLICY_LEGACY,
190 .apsd_conf = {0, 0},
191 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200192 [CONF_TX_AC_VI] = {
193 .queue_id = CONF_TX_AC_VI,
194 .channel_type = CONF_CHANNEL_TYPE_EDCF,
195 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .ps_scheme = CONF_PS_SCHEME_LEGACY,
197 .ack_policy = CONF_ACK_POLICY_LEGACY,
198 .apsd_conf = {0, 0},
199 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200200 [CONF_TX_AC_VO] = {
201 .queue_id = CONF_TX_AC_VO,
202 .channel_type = CONF_CHANNEL_TYPE_EDCF,
203 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300204 .ps_scheme = CONF_PS_SCHEME_LEGACY,
205 .ack_policy = CONF_ACK_POLICY_LEGACY,
206 .apsd_conf = {0, 0},
207 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300208 },
209 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200210 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300211 .tx_compl_threshold = 4,
212 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
213 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200214 .tmpl_short_retry_limit = 10,
215 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300216 },
217 .conn = {
218 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300219 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300221 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300222 .bcn_filt_ie = {
223 [0] = {
224 .ie = WLAN_EID_CHANNEL_SWITCH,
225 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300226 },
227 [1] = {
228 .ie = WLAN_EID_HT_INFORMATION,
229 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
230 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200232 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 .bss_lose_timeout = 100,
234 .beacon_rx_timeout = 10000,
235 .broadcast_timeout = 20000,
236 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300237 .ps_poll_threshold = 10,
238 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300239 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e02011-03-14 18:53:10 +0200240 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300241 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300242 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200243 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300244 .keep_alive_interval = 55000,
245 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300246 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200247 .itrim = {
248 .enable = false,
249 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200250 },
251 .pm_config = {
252 .host_clk_settling_time = 5000,
253 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 },
255 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300256 .trigger_pacing = 1,
257 .avg_weight_rssi_beacon = 20,
258 .avg_weight_rssi_data = 10,
259 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100260 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200261 },
262 .scan = {
263 .min_dwell_time_active = 7500,
264 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100265 .min_dwell_time_passive = 100000,
266 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200267 .num_probe_reqs = 2,
268 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300269 .sched_scan = {
270 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300271 .min_dwell_time_active = 30,
272 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300274 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300275 .num_probe_reqs = 2,
276 .rssi_threshold = -90,
277 .snr_threshold = 0,
278 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200279 .rf = {
280 .tx_per_channel_power_compensation_2 = {
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 },
283 .tx_per_channel_power_compensation_5 = {
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 },
288 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300290 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100291 .tx_ba_win_size = 64,
292 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300293 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100294 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200295 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200296 .num_stations = 1,
297 .ssid_profiles = 1,
298 .rx_block_num = 70,
299 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300300 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200301 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200302 .min_req_rx_blocks = 22,
303 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200304 },
305 .mem_wl128x = {
306 .num_stations = 1,
307 .ssid_profiles = 1,
308 .rx_block_num = 40,
309 .tx_min_block_num = 40,
310 .dynamic_memory = 1,
311 .min_req_tx_blocks = 45,
312 .min_req_rx_blocks = 22,
313 .tx_min = 27,
314 },
Shahar Leviff868432011-04-11 15:41:46 +0300315 .fm_coex = {
316 .enable = true,
317 .swallow_period = 5,
318 .n_divider_fref_set_1 = 0xff, /* default */
319 .n_divider_fref_set_2 = 12,
320 .m_divider_fref_set_1 = 148,
321 .m_divider_fref_set_2 = 0xffff, /* default */
322 .coex_pll_stabilization_time = 0xffffffff, /* default */
323 .ldo_stabilization_time = 0xffff, /* default */
324 .fm_disturbed_band_margin = 0xff, /* default */
325 .swallow_clk_diff = 0xff, /* default */
326 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300327 .rx_streaming = {
328 .duration = 150,
329 .queues = 0x1,
330 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300331 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300332 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300333 .fwlog = {
334 .mode = WL12XX_FWLOG_ON_DEMAND,
335 .mem_blocks = 2,
336 .severity = 0,
337 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
338 .output = WL12XX_FWLOG_OUTPUT_HOST,
339 .threshold = 0,
340 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300341 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300342 .rate = {
343 .rate_retry_score = 32000,
344 .per_add = 8192,
345 .per_th1 = 2048,
346 .per_th2 = 4096,
347 .max_per = 8100,
348 .inverse_curiosity_factor = 5,
349 .tx_fail_low_th = 4,
350 .tx_fail_high_th = 10,
351 .per_alpha_shift = 4,
352 .per_add_shift = 13,
353 .per_beta1_shift = 10,
354 .per_beta2_shift = 8,
355 .rate_check_up = 2,
356 .rate_check_down = 12,
357 .rate_retry_policy = {
358 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00,
361 },
362 },
Eliad Peller94877752011-08-28 15:11:56 +0300363 .hangover = {
364 .recover_time = 0,
365 .hangover_period = 20,
366 .dynamic_mode = 1,
367 .early_termination_mode = 1,
368 .max_period = 20,
369 .min_period = 1,
370 .increase_delta = 1,
371 .decrease_delta = 2,
372 .quiet_time = 4,
373 .increase_time = 1,
374 .window_size = 16,
375 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300376};
377
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300379static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300380
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300381static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200382 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300383 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200384static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200385static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200386
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200387static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300388static LIST_HEAD(wl_list);
389
Eliad Pellerba8447f2011-10-10 10:13:00 +0200390static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
391 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300392{
393 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200394
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300395 if (operstate != IF_OPER_UP)
396 return 0;
397
Eliad Peller8181aec2011-10-10 10:13:04 +0200398 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300399 return 0;
400
Eliad Peller154da672011-10-05 11:55:53 +0200401 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300402 if (ret < 0)
403 return ret;
404
Eliad Peller0603d892011-10-05 11:55:51 +0200405 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300406
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300407 wl1271_info("Association completed.");
408 return 0;
409}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300410static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
411 void *arg)
412{
413 struct net_device *dev = arg;
414 struct wireless_dev *wdev;
415 struct wiphy *wiphy;
416 struct ieee80211_hw *hw;
417 struct wl1271 *wl;
418 struct wl1271 *wl_temp;
Eliad Pellerba8447f2011-10-10 10:13:00 +0200419 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300420 int ret = 0;
421
422 /* Check that this notification is for us. */
423 if (what != NETDEV_CHANGE)
424 return NOTIFY_DONE;
425
426 wdev = dev->ieee80211_ptr;
427 if (wdev == NULL)
428 return NOTIFY_DONE;
429
430 wiphy = wdev->wiphy;
431 if (wiphy == NULL)
432 return NOTIFY_DONE;
433
434 hw = wiphy_priv(wiphy);
435 if (hw == NULL)
436 return NOTIFY_DONE;
437
438 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200439 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300440 list_for_each_entry(wl, &wl_list, list) {
441 if (wl == wl_temp)
442 break;
443 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200444 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300445 if (wl != wl_temp)
446 return NOTIFY_DONE;
447
448 mutex_lock(&wl->mutex);
449
450 if (wl->state == WL1271_STATE_OFF)
451 goto out;
452
Eliad Peller6ab70912011-12-18 20:25:45 +0200453 if (dev->operstate != IF_OPER_UP)
454 goto out;
455 /*
456 * The correct behavior should be just getting the appropriate wlvif
457 * from the given dev, but currently we don't have a mac80211
458 * interface for it.
459 */
Eliad Pellerba8447f2011-10-10 10:13:00 +0200460 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller6ab70912011-12-18 20:25:45 +0200461 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
462
Eliad Pellerba8447f2011-10-10 10:13:00 +0200463 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
464 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300465
Eliad Pellerba8447f2011-10-10 10:13:00 +0200466 ret = wl1271_ps_elp_wakeup(wl);
467 if (ret < 0)
468 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300469
Eliad Peller6ab70912011-12-18 20:25:45 +0200470 wl1271_check_operstate(wl, wlvif,
471 ieee80211_get_operstate(vif));
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300472
Eliad Pellerba8447f2011-10-10 10:13:00 +0200473 wl1271_ps_elp_sleep(wl);
474 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300475out:
476 mutex_unlock(&wl->mutex);
477
478 return NOTIFY_OK;
479}
480
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100481static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200482 struct regulatory_request *request)
483{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100484 struct ieee80211_supported_band *band;
485 struct ieee80211_channel *ch;
486 int i;
487
488 band = wiphy->bands[IEEE80211_BAND_5GHZ];
489 for (i = 0; i < band->n_channels; i++) {
490 ch = &band->channels[i];
491 if (ch->flags & IEEE80211_CHAN_DISABLED)
492 continue;
493
494 if (ch->flags & IEEE80211_CHAN_RADAR)
495 ch->flags |= IEEE80211_CHAN_NO_IBSS |
496 IEEE80211_CHAN_PASSIVE_SCAN;
497
498 }
499
500 return 0;
501}
502
Eliad Peller9eb599e2011-10-10 10:12:59 +0200503static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
504 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300505{
506 int ret = 0;
507
508 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200509 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300510 if (ret < 0)
511 goto out;
512
513 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200514 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300515 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200516 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300517out:
518 return ret;
519}
520
521/*
522 * this function is being called when the rx_streaming interval
523 * has beed changed or rx_streaming should be disabled
524 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200525int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300526{
527 int ret = 0;
528 int period = wl->conf.rx_streaming.interval;
529
530 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200531 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300532 goto out;
533
534 /* reconfigure/disable according to new streaming_period */
535 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200536 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300537 (wl->conf.rx_streaming.always ||
538 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200539 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300540 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200541 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300542 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200543 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300544 }
545out:
546 return ret;
547}
548
549static void wl1271_rx_streaming_enable_work(struct work_struct *work)
550{
551 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200552 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
553 rx_streaming_enable_work);
554 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300555
556 mutex_lock(&wl->mutex);
557
Eliad Peller0744bdb2011-10-10 10:13:05 +0200558 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200559 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300560 (!wl->conf.rx_streaming.always &&
561 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
562 goto out;
563
564 if (!wl->conf.rx_streaming.interval)
565 goto out;
566
567 ret = wl1271_ps_elp_wakeup(wl);
568 if (ret < 0)
569 goto out;
570
Eliad Peller9eb599e2011-10-10 10:12:59 +0200571 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300572 if (ret < 0)
573 goto out_sleep;
574
575 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200576 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300577 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
578
579out_sleep:
580 wl1271_ps_elp_sleep(wl);
581out:
582 mutex_unlock(&wl->mutex);
583}
584
585static void wl1271_rx_streaming_disable_work(struct work_struct *work)
586{
587 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200588 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
589 rx_streaming_disable_work);
590 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300591
592 mutex_lock(&wl->mutex);
593
Eliad Peller0744bdb2011-10-10 10:13:05 +0200594 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300595 goto out;
596
597 ret = wl1271_ps_elp_wakeup(wl);
598 if (ret < 0)
599 goto out;
600
Eliad Peller9eb599e2011-10-10 10:12:59 +0200601 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300602 if (ret)
603 goto out_sleep;
604
605out_sleep:
606 wl1271_ps_elp_sleep(wl);
607out:
608 mutex_unlock(&wl->mutex);
609}
610
611static void wl1271_rx_streaming_timer(unsigned long data)
612{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200613 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
614 struct wl1271 *wl = wlvif->wl;
615 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300616}
617
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300618static void wl1271_conf_init(struct wl1271 *wl)
619{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300620
621 /*
622 * This function applies the default configuration to the driver. This
623 * function is invoked upon driver load (spi probe.)
624 *
625 * The configuration is stored in a run-time structure in order to
626 * facilitate for run-time adjustment of any of the parameters. Making
627 * changes to the configuration structure will apply the new values on
628 * the next interface up (wl1271_op_start.)
629 */
630
631 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300632 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300633
Ido Yariv95dac04f2011-06-06 14:57:06 +0300634 /* Adjust settings according to optional module parameters */
635 if (fwlog_param) {
636 if (!strcmp(fwlog_param, "continuous")) {
637 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
638 } else if (!strcmp(fwlog_param, "ondemand")) {
639 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
640 } else if (!strcmp(fwlog_param, "dbgpins")) {
641 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
642 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
643 } else if (!strcmp(fwlog_param, "disable")) {
644 wl->conf.fwlog.mem_blocks = 0;
645 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
646 } else {
647 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
648 }
649 }
650}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300651
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300652static int wl1271_plt_init(struct wl1271 *wl)
653{
Eliad Peller188e7f52011-12-06 12:15:06 +0200654 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300655
Shahar Levi49d750ca2011-03-06 16:32:09 +0200656 if (wl->chip.id == CHIP_ID_1283_PG20)
657 ret = wl128x_cmd_general_parms(wl);
658 else
659 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200660 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200661 return ret;
662
Shahar Levi49d750ca2011-03-06 16:32:09 +0200663 if (wl->chip.id == CHIP_ID_1283_PG20)
664 ret = wl128x_cmd_radio_parms(wl);
665 else
666 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200667 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200668 return ret;
669
Shahar Levi49d750ca2011-03-06 16:32:09 +0200670 if (wl->chip.id != CHIP_ID_1283_PG20) {
671 ret = wl1271_cmd_ext_radio_parms(wl);
672 if (ret < 0)
673 return ret;
674 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200675 if (ret < 0)
676 return ret;
677
Shahar Levi48a61472011-03-06 16:32:08 +0200678 /* Chip-specific initializations */
679 ret = wl1271_chip_specific_init(wl);
680 if (ret < 0)
681 return ret;
682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 ret = wl1271_acx_init_mem_config(wl);
684 if (ret < 0)
685 return ret;
686
Eliad Peller7f0979882011-08-14 13:17:06 +0300687 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600688 if (ret < 0)
689 goto out_free_memmap;
690
Luciano Coelho12419cc2010-02-18 13:25:44 +0200691 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200692 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300693 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200694 goto out_free_memmap;
695
696 /* Configure for CAM power saving (ie. always active) */
697 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
698 if (ret < 0)
699 goto out_free_memmap;
700
701 /* configure PM */
702 ret = wl1271_acx_pm_config(wl);
703 if (ret < 0)
704 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300705
706 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200707
708 out_free_memmap:
709 kfree(wl->target_mem_map);
710 wl->target_mem_map = NULL;
711
712 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713}
714
Eliad Peller6e8cd332011-10-10 10:13:13 +0200715static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
716 struct wl12xx_vif *wlvif,
717 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200718{
Arik Nemtsovda032092011-08-25 12:43:15 +0300719 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200720
Arik Nemtsovb622d992011-02-23 00:22:31 +0200721 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300722 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200723
724 /*
725 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300726 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200727 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300728 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200729 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200730
Arik Nemtsovda032092011-08-25 12:43:15 +0300731 /*
732 * Start high-level PS if the STA is asleep with enough blocks in FW.
733 * Make an exception if this is the only connected station. In this
734 * case FW-memory congestion is not a problem.
735 */
736 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200737 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200738}
739
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300740static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200741 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300742 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200743{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200744 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200745 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300746 u8 hlid, cnt;
747
748 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200749
750 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
751 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
752 wl1271_debug(DEBUG_PSM,
753 "link ps prev 0x%x cur 0x%x changed 0x%x",
754 wl->ap_fw_ps_map, cur_fw_ps_map,
755 wl->ap_fw_ps_map ^ cur_fw_ps_map);
756
757 wl->ap_fw_ps_map = cur_fw_ps_map;
758 }
759
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200760 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
761 lnk = &wl->links[hlid];
762 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200763
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200764 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
765 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200766
Eliad Peller6e8cd332011-10-10 10:13:13 +0200767 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
768 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200769 }
770}
771
Eliad Peller4d56ad92011-08-14 13:17:05 +0300772static void wl12xx_fw_status(struct wl1271 *wl,
773 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300774{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200775 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200776 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200777 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300778 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300779 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300780
Eliad Peller4d56ad92011-08-14 13:17:05 +0300781 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200782
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300783 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
784 "drv_rx_counter = %d, tx_results_counter = %d)",
785 status->intr,
786 status->fw_rx_counter,
787 status->drv_rx_counter,
788 status->tx_results_counter);
789
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300790 for (i = 0; i < NUM_TX_QUEUES; i++) {
791 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300792 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300793 (status->tx_released_pkts[i] -
794 wl->tx_pkts_freed[i]) & 0xff;
795
796 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
797 }
798
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300799 /* prevent wrap-around in total blocks counter */
800 if (likely(wl->tx_blocks_freed <=
801 le32_to_cpu(status->total_released_blks)))
802 freed_blocks = le32_to_cpu(status->total_released_blks) -
803 wl->tx_blocks_freed;
804 else
805 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
806 le32_to_cpu(status->total_released_blks);
807
Eliad Peller4d56ad92011-08-14 13:17:05 +0300808 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200809
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300810 wl->tx_allocated_blocks -= freed_blocks;
811
Eliad Peller4d56ad92011-08-14 13:17:05 +0300812 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200813
Eliad Peller4d56ad92011-08-14 13:17:05 +0300814 /*
815 * The FW might change the total number of TX memblocks before
816 * we get a notification about blocks being released. Thus, the
817 * available blocks calculation might yield a temporary result
818 * which is lower than the actual available blocks. Keeping in
819 * mind that only blocks that were allocated can be moved from
820 * TX to RX, tx_blocks_available should never decrease here.
821 */
822 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
823 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300824
Ido Yariva5225502010-10-12 14:49:10 +0200825 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200826 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200827 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828
Eliad Peller4d56ad92011-08-14 13:17:05 +0300829 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200830 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200831 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200832 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300833
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200835 getnstimeofday(&ts);
836 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
837 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300838}
839
Ido Yariva6208652011-03-01 15:14:41 +0200840static void wl1271_flush_deferred_work(struct wl1271 *wl)
841{
842 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200843
Ido Yariva6208652011-03-01 15:14:41 +0200844 /* Pass all received frames to the network stack */
845 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
846 ieee80211_rx_ni(wl->hw, skb);
847
848 /* Return sent skbs to the network stack */
849 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300850 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200851}
852
853static void wl1271_netstack_work(struct work_struct *work)
854{
855 struct wl1271 *wl =
856 container_of(work, struct wl1271, netstack_work);
857
858 do {
859 wl1271_flush_deferred_work(wl);
860 } while (skb_queue_len(&wl->deferred_rx_queue));
861}
862
863#define WL1271_IRQ_MAX_LOOPS 256
864
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300865static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300866{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300867 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300868 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200869 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200870 struct wl1271 *wl = (struct wl1271 *)cookie;
871 bool done = false;
872 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200873 unsigned long flags;
874
875 /* TX might be handled here, avoid redundant work */
876 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
877 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878
Ido Yariv341b7cd2011-03-31 10:07:01 +0200879 /*
880 * In case edge triggered interrupt must be used, we cannot iterate
881 * more than once without introducing race conditions with the hardirq.
882 */
883 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
884 loopcount = 1;
885
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300886 mutex_lock(&wl->mutex);
887
888 wl1271_debug(DEBUG_IRQ, "IRQ work");
889
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200890 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300891 goto out;
892
Ido Yariva6208652011-03-01 15:14:41 +0200893 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300894 if (ret < 0)
895 goto out;
896
Ido Yariva6208652011-03-01 15:14:41 +0200897 while (!done && loopcount--) {
898 /*
899 * In order to avoid a race with the hardirq, clear the flag
900 * before acknowledging the chip. Since the mutex is held,
901 * wl1271_ps_elp_wakeup cannot be called concurrently.
902 */
903 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
904 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200905
Eliad Peller4d56ad92011-08-14 13:17:05 +0300906 wl12xx_fw_status(wl, wl->fw_status);
907 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200908 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200909 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200910 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200911 continue;
912 }
913
Eliad Pellerccc83b02010-10-27 14:09:57 +0200914 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
915 wl1271_error("watchdog interrupt received! "
916 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300917 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200918
919 /* restarting the chip. ignore any other interrupt. */
920 goto out;
921 }
922
Ido Yariva6208652011-03-01 15:14:41 +0200923 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200924 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
925
Eliad Peller4d56ad92011-08-14 13:17:05 +0300926 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200927
Ido Yariva5225502010-10-12 14:49:10 +0200928 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200929 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200930 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300931 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200932 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200933 /*
934 * In order to avoid starvation of the TX path,
935 * call the work function directly.
936 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200937 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200938 } else {
939 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200940 }
941
Ido Yariv8aad2462011-03-01 15:14:38 +0200942 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300943 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200944 (wl->tx_results_count & 0xff))
945 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200946
947 /* Make sure the deferred queues don't get too long */
948 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
949 skb_queue_len(&wl->deferred_rx_queue);
950 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
951 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200952 }
953
954 if (intr & WL1271_ACX_INTR_EVENT_A) {
955 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
956 wl1271_event_handle(wl, 0);
957 }
958
959 if (intr & WL1271_ACX_INTR_EVENT_B) {
960 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
961 wl1271_event_handle(wl, 1);
962 }
963
964 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
965 wl1271_debug(DEBUG_IRQ,
966 "WL1271_ACX_INTR_INIT_COMPLETE");
967
968 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
969 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970 }
971
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972 wl1271_ps_elp_sleep(wl);
973
974out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200975 spin_lock_irqsave(&wl->wl_lock, flags);
976 /* In case TX was not handled here, queue TX work */
977 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
978 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300979 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200980 ieee80211_queue_work(wl->hw, &wl->tx_work);
981 spin_unlock_irqrestore(&wl->wl_lock, flags);
982
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200984
985 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300986}
987
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988static int wl1271_fetch_firmware(struct wl1271 *wl)
989{
990 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200991 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300992 int ret;
993
Arik Nemtsovc302b2c2011-08-17 10:45:48 +0300994 if (wl->chip.id == CHIP_ID_1283_PG20)
995 fw_name = WL128X_FW_NAME;
996 else
997 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200998
999 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1000
Felipe Balbia390e852011-10-06 10:07:44 +03001001 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001002
1003 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001004 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001005 return ret;
1006 }
1007
1008 if (fw->size % 4) {
1009 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1010 fw->size);
1011 ret = -EILSEQ;
1012 goto out;
1013 }
1014
Arik Nemtsov166d5042010-10-16 21:44:57 +02001015 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001017 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018
1019 if (!wl->fw) {
1020 wl1271_error("could not allocate memory for the firmware");
1021 ret = -ENOMEM;
1022 goto out;
1023 }
1024
1025 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026 ret = 0;
1027
1028out:
1029 release_firmware(fw);
1030
1031 return ret;
1032}
1033
1034static int wl1271_fetch_nvs(struct wl1271 *wl)
1035{
1036 const struct firmware *fw;
1037 int ret;
1038
Felipe Balbia390e852011-10-06 10:07:44 +03001039 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040
1041 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001042 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
1043 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001044 return ret;
1045 }
1046
Shahar Levibc765bf2011-03-06 16:32:10 +02001047 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048
1049 if (!wl->nvs) {
1050 wl1271_error("could not allocate memory for the nvs file");
1051 ret = -ENOMEM;
1052 goto out;
1053 }
1054
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001055 wl->nvs_len = fw->size;
1056
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057out:
1058 release_firmware(fw);
1059
1060 return ret;
1061}
1062
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001063void wl12xx_queue_recovery_work(struct wl1271 *wl)
1064{
1065 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1066 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1067}
1068
Ido Yariv95dac04f2011-06-06 14:57:06 +03001069size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1070{
1071 size_t len = 0;
1072
1073 /* The FW log is a length-value list, find where the log end */
1074 while (len < maxlen) {
1075 if (memblock[len] == 0)
1076 break;
1077 if (len + memblock[len] + 1 > maxlen)
1078 break;
1079 len += memblock[len] + 1;
1080 }
1081
1082 /* Make sure we have enough room */
1083 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1084
1085 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1086 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1087 wl->fwlog_size += len;
1088
1089 return len;
1090}
1091
1092static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1093{
1094 u32 addr;
1095 u32 first_addr;
1096 u8 *block;
1097
1098 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1099 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1100 (wl->conf.fwlog.mem_blocks == 0))
1101 return;
1102
1103 wl1271_info("Reading FW panic log");
1104
1105 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1106 if (!block)
1107 return;
1108
1109 /*
1110 * Make sure the chip is awake and the logger isn't active.
1111 * This might fail if the firmware hanged.
1112 */
1113 if (!wl1271_ps_elp_wakeup(wl))
1114 wl12xx_cmd_stop_fwlog(wl);
1115
1116 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001117 wl12xx_fw_status(wl, wl->fw_status);
1118 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001119 if (!first_addr)
1120 goto out;
1121
1122 /* Traverse the memory blocks linked list */
1123 addr = first_addr;
1124 do {
1125 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1126 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1127 false);
1128
1129 /*
1130 * Memory blocks are linked to one another. The first 4 bytes
1131 * of each memory block hold the hardware address of the next
1132 * one. The last memory block points to the first one.
1133 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001134 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001135 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1136 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1137 break;
1138 } while (addr && (addr != first_addr));
1139
1140 wake_up_interruptible(&wl->fwlog_waitq);
1141
1142out:
1143 kfree(block);
1144}
1145
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001146static void wl1271_recovery_work(struct work_struct *work)
1147{
1148 struct wl1271 *wl =
1149 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001150 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001151 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001152
1153 mutex_lock(&wl->mutex);
1154
1155 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001156 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001157
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001158 /* Avoid a recursive recovery */
1159 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1160
Ido Yariv95dac04f2011-06-06 14:57:06 +03001161 wl12xx_read_fwlog_panic(wl);
1162
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001163 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1164 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001165
Eliad Peller2a5bff02011-08-25 18:10:59 +03001166 BUG_ON(bug_on_recovery);
1167
Oz Krakowskib992c682011-06-26 10:36:02 +03001168 /*
1169 * Advance security sequence number to overcome potential progress
1170 * in the firmware during recovery. This doens't hurt if the network is
1171 * not encrypted.
1172 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001173 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001174 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001175 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001176 wlvif->tx_security_seq +=
1177 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1178 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001179
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001180 /* Prevent spurious TX during FW restart */
1181 ieee80211_stop_queues(wl->hw);
1182
Luciano Coelho33c2c062011-05-10 14:46:02 +03001183 if (wl->sched_scanning) {
1184 ieee80211_sched_scan_stopped(wl->hw);
1185 wl->sched_scanning = false;
1186 }
1187
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001188 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001189 while (!list_empty(&wl->wlvif_list)) {
1190 wlvif = list_first_entry(&wl->wlvif_list,
1191 struct wl12xx_vif, list);
1192 vif = wl12xx_wlvif_to_vif(wlvif);
1193 __wl1271_op_remove_interface(wl, vif, false);
1194 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001195 mutex_unlock(&wl->mutex);
1196 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001197
1198 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1199
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001200 ieee80211_restart_hw(wl->hw);
1201
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001202 /*
1203 * Its safe to enable TX now - the queues are stopped after a request
1204 * to restart the HW.
1205 */
1206 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001207 return;
1208out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001209 mutex_unlock(&wl->mutex);
1210}
1211
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001212static void wl1271_fw_wakeup(struct wl1271 *wl)
1213{
1214 u32 elp_reg;
1215
1216 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001217 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218}
1219
1220static int wl1271_setup(struct wl1271 *wl)
1221{
1222 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1223 if (!wl->fw_status)
1224 return -ENOMEM;
1225
1226 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1227 if (!wl->tx_res_if) {
1228 kfree(wl->fw_status);
1229 return -ENOMEM;
1230 }
1231
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001232 return 0;
1233}
1234
1235static int wl1271_chip_wakeup(struct wl1271 *wl)
1236{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001237 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001238 int ret = 0;
1239
Juuso Oikarinen01ac17ec2009-12-11 15:41:02 +02001240 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001241 ret = wl1271_power_on(wl);
1242 if (ret < 0)
1243 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001244 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001245 wl1271_io_reset(wl);
1246 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247
1248 /* We don't need a real memory partition here, because we only want
1249 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001250 memset(&partition, 0, sizeof(partition));
1251 partition.reg.start = REGISTERS_BASE;
1252 partition.reg.size = REGISTERS_DOWN_SIZE;
1253 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254
1255 /* ELP module wake up */
1256 wl1271_fw_wakeup(wl);
1257
1258 /* whal_FwCtrl_BootSm() */
1259
1260 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001261 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001262
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001263 /*
1264 * For wl127x based devices we could use the default block
1265 * size (512 bytes), but due to a bug in the sdio driver, we
1266 * need to set it explicitly after the chip is powered on. To
1267 * simplify the code and since the performance impact is
1268 * negligible, we use the same block size for all different
1269 * chip types.
1270 */
1271 if (!wl1271_set_block_size(wl))
1272 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273
1274 switch (wl->chip.id) {
1275 case CHIP_ID_1271_PG10:
1276 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1277 wl->chip.id);
1278
1279 ret = wl1271_setup(wl);
1280 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001281 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001282 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001284
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 case CHIP_ID_1271_PG20:
1286 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1287 wl->chip.id);
1288
1289 ret = wl1271_setup(wl);
1290 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001291 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001292 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001293 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001294
Shahar Levi0830cee2011-03-06 16:32:20 +02001295 case CHIP_ID_1283_PG20:
1296 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1297 wl->chip.id);
1298
1299 ret = wl1271_setup(wl);
1300 if (ret < 0)
1301 goto out;
1302 break;
1303 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001304 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001305 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001307 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001308 }
1309
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001310 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001311 ret = wl1271_fetch_firmware(wl);
1312 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001313 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314 }
1315
1316 /* No NVS from netlink, try to get it from the filesystem */
1317 if (wl->nvs == NULL) {
1318 ret = wl1271_fetch_nvs(wl);
1319 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001320 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321 }
1322
1323out:
1324 return ret;
1325}
1326
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327int wl1271_plt_start(struct wl1271 *wl)
1328{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001329 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001330 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331 int ret;
1332
1333 mutex_lock(&wl->mutex);
1334
1335 wl1271_notice("power up");
1336
1337 if (wl->state != WL1271_STATE_OFF) {
1338 wl1271_error("cannot go into PLT state because not "
1339 "in off state: %d", wl->state);
1340 ret = -EBUSY;
1341 goto out;
1342 }
1343
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001344 while (retries) {
1345 retries--;
1346 ret = wl1271_chip_wakeup(wl);
1347 if (ret < 0)
1348 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001349
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001350 ret = wl1271_boot(wl);
1351 if (ret < 0)
1352 goto power_off;
1353
1354 ret = wl1271_plt_init(wl);
1355 if (ret < 0)
1356 goto irq_disable;
1357
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001358 wl->state = WL1271_STATE_PLT;
1359 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001360 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001361
Gery Kahn6f07b722011-07-18 14:21:49 +03001362 /* update hw/fw version info in wiphy struct */
1363 wiphy->hw_version = wl->chip.id;
1364 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1365 sizeof(wiphy->fw_version));
1366
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367 goto out;
1368
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001369irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001370 mutex_unlock(&wl->mutex);
1371 /* Unlocking the mutex in the middle of handling is
1372 inherently unsafe. In this case we deem it safe to do,
1373 because we need to let any possibly pending IRQ out of
1374 the system (and while we are WL1271_STATE_OFF the IRQ
1375 work function will not do anything.) Also, any other
1376 possible concurrent operations will fail due to the
1377 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001378 wl1271_disable_interrupts(wl);
1379 wl1271_flush_deferred_work(wl);
1380 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001381 mutex_lock(&wl->mutex);
1382power_off:
1383 wl1271_power_off(wl);
1384 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001386 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1387 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001388out:
1389 mutex_unlock(&wl->mutex);
1390
1391 return ret;
1392}
1393
Luciano Coelho4623ec72011-03-21 19:26:41 +02001394static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001395{
1396 int ret = 0;
1397
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001398 wl1271_notice("power down");
1399
1400 if (wl->state != WL1271_STATE_PLT) {
1401 wl1271_error("cannot power down because not in PLT "
1402 "state: %d", wl->state);
1403 ret = -EBUSY;
1404 goto out;
1405 }
1406
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407 wl1271_power_off(wl);
1408
1409 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001410 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001411
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001412 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001413 wl1271_disable_interrupts(wl);
1414 wl1271_flush_deferred_work(wl);
1415 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001416 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001417 mutex_lock(&wl->mutex);
1418out:
1419 return ret;
1420}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001421
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001422int wl1271_plt_stop(struct wl1271 *wl)
1423{
1424 int ret;
1425
1426 mutex_lock(&wl->mutex);
1427 ret = __wl1271_plt_stop(wl);
1428 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429 return ret;
1430}
1431
Johannes Berg7bb45682011-02-24 14:42:06 +01001432static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001433{
1434 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001435 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1436 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001437 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001438 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001439 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001440 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441
Eliad Peller0f168012011-10-11 13:52:25 +02001442 if (vif)
1443 wlvif = wl12xx_vif_to_data(vif);
1444
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001445 mapping = skb_get_queue_mapping(skb);
1446 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001447
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001448 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001449
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001450 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001451
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001452 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001453 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001454 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001455 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001456 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001457 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001458 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001459
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001460 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1461 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1462
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001463 wl->tx_queue_count[q]++;
1464
1465 /*
1466 * The workqueue is slow to process the tx_queue and we need stop
1467 * the queue here, otherwise the queue will get too long.
1468 */
1469 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1470 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1471 ieee80211_stop_queue(wl->hw, mapping);
1472 set_bit(q, &wl->stopped_queues_map);
1473 }
1474
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001475 /*
1476 * The chip specific setup must run before the first TX packet -
1477 * before that, the tx_work will not be initialized!
1478 */
1479
Ido Yarivb07d4032011-03-01 15:14:43 +02001480 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1481 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001482 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001483
Arik Nemtsov04216da2011-08-14 13:17:38 +03001484out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001485 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486}
1487
Shahar Leviae47c452011-03-06 16:32:14 +02001488int wl1271_tx_dummy_packet(struct wl1271 *wl)
1489{
Ido Yariv990f5de2011-03-31 10:06:59 +02001490 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001491 int q;
1492
1493 /* no need to queue a new dummy packet if one is already pending */
1494 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1495 return 0;
1496
1497 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001498
Ido Yariv990f5de2011-03-31 10:06:59 +02001499 spin_lock_irqsave(&wl->wl_lock, flags);
1500 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001501 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001502 spin_unlock_irqrestore(&wl->wl_lock, flags);
1503
1504 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1505 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001506 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001507
1508 /*
1509 * If the FW TX is busy, TX work will be scheduled by the threaded
1510 * interrupt handler function
1511 */
1512 return 0;
1513}
1514
1515/*
1516 * The size of the dummy packet should be at least 1400 bytes. However, in
1517 * order to minimize the number of bus transactions, aligning it to 512 bytes
1518 * boundaries could be beneficial, performance wise
1519 */
1520#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1521
Luciano Coelhocf27d862011-04-01 21:08:23 +03001522static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001523{
1524 struct sk_buff *skb;
1525 struct ieee80211_hdr_3addr *hdr;
1526 unsigned int dummy_packet_size;
1527
1528 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1529 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1530
1531 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001532 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001533 wl1271_warning("Failed to allocate a dummy packet skb");
1534 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001535 }
1536
1537 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1538
1539 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1540 memset(hdr, 0, sizeof(*hdr));
1541 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001542 IEEE80211_STYPE_NULLFUNC |
1543 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001544
Ido Yariv990f5de2011-03-31 10:06:59 +02001545 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001546
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001547 /* Dummy packets require the TID to be management */
1548 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001549
1550 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001551 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001552 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001553
Ido Yariv990f5de2011-03-31 10:06:59 +02001554 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001555}
1556
Ido Yariv990f5de2011-03-31 10:06:59 +02001557
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001558static struct notifier_block wl1271_dev_notifier = {
1559 .notifier_call = wl1271_dev_notify,
1560};
1561
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001562#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001563static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1564 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001565{
Eliad Pellere85d1622011-06-27 13:06:43 +03001566 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001567
Eliad Peller94390642011-05-13 11:57:13 +03001568 mutex_lock(&wl->mutex);
1569
Eliad Pellerba8447f2011-10-10 10:13:00 +02001570 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001571 goto out_unlock;
1572
Eliad Peller94390642011-05-13 11:57:13 +03001573 ret = wl1271_ps_elp_wakeup(wl);
1574 if (ret < 0)
1575 goto out_unlock;
1576
1577 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001578 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001579 DECLARE_COMPLETION_ONSTACK(compl);
1580
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001581 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001582 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001583 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001584 if (ret < 0)
1585 goto out_sleep;
1586
1587 /* we must unlock here so we will be able to get events */
1588 wl1271_ps_elp_sleep(wl);
1589 mutex_unlock(&wl->mutex);
1590
1591 ret = wait_for_completion_timeout(
1592 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
Pontus Fuchsef187062011-12-14 14:32:23 +01001593
1594 mutex_lock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001595 if (ret <= 0) {
1596 wl1271_warning("couldn't enter ps mode!");
1597 ret = -EBUSY;
Pontus Fuchsef187062011-12-14 14:32:23 +01001598 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001599 }
1600
Eliad Peller94390642011-05-13 11:57:13 +03001601 ret = wl1271_ps_elp_wakeup(wl);
1602 if (ret < 0)
Pontus Fuchsef187062011-12-14 14:32:23 +01001603 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001604 }
1605out_sleep:
1606 wl1271_ps_elp_sleep(wl);
Pontus Fuchsef187062011-12-14 14:32:23 +01001607out_cleanup:
1608 wlvif->ps_compl = NULL;
Eliad Peller94390642011-05-13 11:57:13 +03001609out_unlock:
1610 mutex_unlock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001611 return ret;
1612
1613}
1614
Eliad Peller0603d892011-10-05 11:55:51 +02001615static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1616 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001617{
Eliad Pellere85d1622011-06-27 13:06:43 +03001618 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001619
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001620 mutex_lock(&wl->mutex);
1621
Eliad Peller53d40d02011-10-10 10:13:02 +02001622 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001623 goto out_unlock;
1624
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001625 ret = wl1271_ps_elp_wakeup(wl);
1626 if (ret < 0)
1627 goto out_unlock;
1628
Eliad Peller0603d892011-10-05 11:55:51 +02001629 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001630
1631 wl1271_ps_elp_sleep(wl);
1632out_unlock:
1633 mutex_unlock(&wl->mutex);
1634 return ret;
1635
1636}
1637
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001638static int wl1271_configure_suspend(struct wl1271 *wl,
1639 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001640{
Eliad Peller536129c2011-10-05 11:55:45 +02001641 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001642 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001643 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001644 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001645 return 0;
1646}
1647
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001648static void wl1271_configure_resume(struct wl1271 *wl,
1649 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001650{
1651 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001652 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1653 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001654
1655 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001656 return;
1657
1658 mutex_lock(&wl->mutex);
1659 ret = wl1271_ps_elp_wakeup(wl);
1660 if (ret < 0)
1661 goto out;
1662
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001663 if (is_sta) {
1664 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001665 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001666 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001667 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001668 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001669 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001670 }
Eliad Peller94390642011-05-13 11:57:13 +03001671
1672 wl1271_ps_elp_sleep(wl);
1673out:
1674 mutex_unlock(&wl->mutex);
1675}
1676
Eliad Peller402e48612011-05-13 11:57:09 +03001677static int wl1271_op_suspend(struct ieee80211_hw *hw,
1678 struct cfg80211_wowlan *wow)
1679{
1680 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001681 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001682 int ret;
1683
Eliad Peller402e48612011-05-13 11:57:09 +03001684 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001685 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001686
Eliad Peller4a859df2011-06-06 12:21:52 +03001687 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001688 wl12xx_for_each_wlvif(wl, wlvif) {
1689 ret = wl1271_configure_suspend(wl, wlvif);
1690 if (ret < 0) {
1691 wl1271_warning("couldn't prepare device to suspend");
1692 return ret;
1693 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001694 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001695 /* flush any remaining work */
1696 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001697
1698 /*
1699 * disable and re-enable interrupts in order to flush
1700 * the threaded_irq
1701 */
1702 wl1271_disable_interrupts(wl);
1703
1704 /*
1705 * set suspended flag to avoid triggering a new threaded_irq
1706 * work. no need for spinlock as interrupts are disabled.
1707 */
1708 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1709
1710 wl1271_enable_interrupts(wl);
1711 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001712 wl12xx_for_each_wlvif(wl, wlvif) {
1713 flush_delayed_work(&wlvif->pspoll_work);
1714 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001715 flush_delayed_work(&wl->elp_work);
1716
Eliad Peller402e48612011-05-13 11:57:09 +03001717 return 0;
1718}
1719
1720static int wl1271_op_resume(struct ieee80211_hw *hw)
1721{
1722 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001723 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001724 unsigned long flags;
1725 bool run_irq_work = false;
1726
Eliad Peller402e48612011-05-13 11:57:09 +03001727 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1728 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001729 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001730
1731 /*
1732 * re-enable irq_work enqueuing, and call irq_work directly if
1733 * there is a pending work.
1734 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001735 spin_lock_irqsave(&wl->wl_lock, flags);
1736 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1737 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1738 run_irq_work = true;
1739 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001740
Eliad Peller4a859df2011-06-06 12:21:52 +03001741 if (run_irq_work) {
1742 wl1271_debug(DEBUG_MAC80211,
1743 "run postponed irq_work directly");
1744 wl1271_irq(0, wl);
1745 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001746 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001747 wl12xx_for_each_wlvif(wl, wlvif) {
1748 wl1271_configure_resume(wl, wlvif);
1749 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001750 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001751
Eliad Peller402e48612011-05-13 11:57:09 +03001752 return 0;
1753}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001754#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001755
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001756static int wl1271_op_start(struct ieee80211_hw *hw)
1757{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001758 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1759
1760 /*
1761 * We have to delay the booting of the hardware because
1762 * we need to know the local MAC address before downloading and
1763 * initializing the firmware. The MAC address cannot be changed
1764 * after boot, and without the proper MAC address, the firmware
1765 * will not function properly.
1766 *
1767 * The MAC address is first known when the corresponding interface
1768 * is added. That is where we will initialize the hardware.
1769 */
1770
1771 return 0;
1772}
1773
1774static void wl1271_op_stop(struct ieee80211_hw *hw)
1775{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001776 struct wl1271 *wl = hw->priv;
1777 int i;
1778
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001779 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001780
Eliad Peller10c8cd02011-10-10 10:13:06 +02001781 mutex_lock(&wl->mutex);
1782 if (wl->state == WL1271_STATE_OFF) {
1783 mutex_unlock(&wl->mutex);
1784 return;
1785 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001786 /*
1787 * this must be before the cancel_work calls below, so that the work
1788 * functions don't perform further work.
1789 */
1790 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001791 mutex_unlock(&wl->mutex);
1792
1793 mutex_lock(&wl_list_mutex);
1794 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001795 mutex_unlock(&wl_list_mutex);
1796
1797 wl1271_disable_interrupts(wl);
1798 wl1271_flush_deferred_work(wl);
1799 cancel_delayed_work_sync(&wl->scan_complete_work);
1800 cancel_work_sync(&wl->netstack_work);
1801 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001802 cancel_delayed_work_sync(&wl->elp_work);
1803
1804 /* let's notify MAC80211 about the remaining pending TX frames */
1805 wl12xx_tx_reset(wl, true);
1806 mutex_lock(&wl->mutex);
1807
1808 wl1271_power_off(wl);
1809
1810 wl->band = IEEE80211_BAND_2GHZ;
1811
1812 wl->rx_counter = 0;
1813 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1814 wl->tx_blocks_available = 0;
1815 wl->tx_allocated_blocks = 0;
1816 wl->tx_results_count = 0;
1817 wl->tx_packets_count = 0;
1818 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001819 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1820 wl->ap_fw_ps_map = 0;
1821 wl->ap_ps_map = 0;
1822 wl->sched_scanning = false;
1823 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1824 memset(wl->links_map, 0, sizeof(wl->links_map));
1825 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1826 wl->active_sta_count = 0;
1827
1828 /* The system link is always allocated */
1829 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1830
1831 /*
1832 * this is performed after the cancel_work calls and the associated
1833 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1834 * get executed before all these vars have been reset.
1835 */
1836 wl->flags = 0;
1837
1838 wl->tx_blocks_freed = 0;
1839
1840 for (i = 0; i < NUM_TX_QUEUES; i++) {
1841 wl->tx_pkts_freed[i] = 0;
1842 wl->tx_allocated_pkts[i] = 0;
1843 }
1844
1845 wl1271_debugfs_reset(wl);
1846
1847 kfree(wl->fw_status);
1848 wl->fw_status = NULL;
1849 kfree(wl->tx_res_if);
1850 wl->tx_res_if = NULL;
1851 kfree(wl->target_mem_map);
1852 wl->target_mem_map = NULL;
1853
1854 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001855}
1856
Eliad Pellere5a359f2011-10-10 10:13:15 +02001857static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1858{
1859 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1860 WL12XX_MAX_RATE_POLICIES);
1861 if (policy >= WL12XX_MAX_RATE_POLICIES)
1862 return -EBUSY;
1863
1864 __set_bit(policy, wl->rate_policies_map);
1865 *idx = policy;
1866 return 0;
1867}
1868
1869static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1870{
1871 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1872 return;
1873
1874 __clear_bit(*idx, wl->rate_policies_map);
1875 *idx = WL12XX_MAX_RATE_POLICIES;
1876}
1877
Eliad Peller536129c2011-10-05 11:55:45 +02001878static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001879{
Eliad Peller536129c2011-10-05 11:55:45 +02001880 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001881 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001882 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001883 return WL1271_ROLE_P2P_GO;
1884 else
1885 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001886
1887 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001888 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001889 return WL1271_ROLE_P2P_CL;
1890 else
1891 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001892
Eliad Peller227e81e2011-08-14 13:17:26 +03001893 case BSS_TYPE_IBSS:
1894 return WL1271_ROLE_IBSS;
1895
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001896 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001897 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001898 }
1899 return WL12XX_INVALID_ROLE_TYPE;
1900}
1901
Eliad Peller83587502011-10-10 10:12:53 +02001902static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001903{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001904 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001905 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001906
Eliad Peller48e93e42011-10-10 10:12:58 +02001907 /* clear everything but the persistent data */
1908 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001909
1910 switch (ieee80211_vif_type_p2p(vif)) {
1911 case NL80211_IFTYPE_P2P_CLIENT:
1912 wlvif->p2p = 1;
1913 /* fall-through */
1914 case NL80211_IFTYPE_STATION:
1915 wlvif->bss_type = BSS_TYPE_STA_BSS;
1916 break;
1917 case NL80211_IFTYPE_ADHOC:
1918 wlvif->bss_type = BSS_TYPE_IBSS;
1919 break;
1920 case NL80211_IFTYPE_P2P_GO:
1921 wlvif->p2p = 1;
1922 /* fall-through */
1923 case NL80211_IFTYPE_AP:
1924 wlvif->bss_type = BSS_TYPE_AP_BSS;
1925 break;
1926 default:
1927 wlvif->bss_type = MAX_BSS_TYPE;
1928 return -EOPNOTSUPP;
1929 }
1930
Eliad Peller0603d892011-10-05 11:55:51 +02001931 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001932 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001933 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001934
Eliad Pellere936bbe2011-10-05 11:55:56 +02001935 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1936 wlvif->bss_type == BSS_TYPE_IBSS) {
1937 /* init sta/ibss data */
1938 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001939 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1940 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1941 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001942 } else {
1943 /* init ap data */
1944 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1945 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001946 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1947 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1948 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1949 wl12xx_allocate_rate_policy(wl,
1950 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001951 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001952
Eliad Peller83587502011-10-10 10:12:53 +02001953 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1954 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001955 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001956 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001957 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001958 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1959
Eliad Peller1b92f152011-10-10 10:13:09 +02001960 /*
1961 * mac80211 configures some values globally, while we treat them
1962 * per-interface. thus, on init, we have to copy them from wl
1963 */
1964 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001965 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001966 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02001967
Eliad Peller9eb599e2011-10-10 10:12:59 +02001968 INIT_WORK(&wlvif->rx_streaming_enable_work,
1969 wl1271_rx_streaming_enable_work);
1970 INIT_WORK(&wlvif->rx_streaming_disable_work,
1971 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02001972 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02001973 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001974
Eliad Peller9eb599e2011-10-10 10:12:59 +02001975 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1976 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001977 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001978}
1979
Eliad Peller1d095472011-10-10 10:12:49 +02001980static bool wl12xx_init_fw(struct wl1271 *wl)
1981{
1982 int retries = WL1271_BOOT_RETRIES;
1983 bool booted = false;
1984 struct wiphy *wiphy = wl->hw->wiphy;
1985 int ret;
1986
1987 while (retries) {
1988 retries--;
1989 ret = wl1271_chip_wakeup(wl);
1990 if (ret < 0)
1991 goto power_off;
1992
1993 ret = wl1271_boot(wl);
1994 if (ret < 0)
1995 goto power_off;
1996
1997 ret = wl1271_hw_init(wl);
1998 if (ret < 0)
1999 goto irq_disable;
2000
2001 booted = true;
2002 break;
2003
2004irq_disable:
2005 mutex_unlock(&wl->mutex);
2006 /* Unlocking the mutex in the middle of handling is
2007 inherently unsafe. In this case we deem it safe to do,
2008 because we need to let any possibly pending IRQ out of
2009 the system (and while we are WL1271_STATE_OFF the IRQ
2010 work function will not do anything.) Also, any other
2011 possible concurrent operations will fail due to the
2012 current state, hence the wl1271 struct should be safe. */
2013 wl1271_disable_interrupts(wl);
2014 wl1271_flush_deferred_work(wl);
2015 cancel_work_sync(&wl->netstack_work);
2016 mutex_lock(&wl->mutex);
2017power_off:
2018 wl1271_power_off(wl);
2019 }
2020
2021 if (!booted) {
2022 wl1271_error("firmware boot failed despite %d retries",
2023 WL1271_BOOT_RETRIES);
2024 goto out;
2025 }
2026
2027 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2028
2029 /* update hw/fw version info in wiphy struct */
2030 wiphy->hw_version = wl->chip.id;
2031 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2032 sizeof(wiphy->fw_version));
2033
2034 /*
2035 * Now we know if 11a is supported (info from the NVS), so disable
2036 * 11a channels if not supported
2037 */
2038 if (!wl->enable_11a)
2039 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2040
2041 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2042 wl->enable_11a ? "" : "not ");
2043
2044 wl->state = WL1271_STATE_ON;
2045out:
2046 return booted;
2047}
2048
Eliad Peller92e712d2011-12-18 20:25:43 +02002049static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2050{
2051 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2052}
2053
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002054static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2055 struct ieee80211_vif *vif)
2056{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002057 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002058 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002059 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002060 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002061 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002062
Johannes Bergc1288b12012-01-19 09:29:57 +01002063 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
2064
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002065 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002066 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002067
2068 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002069 ret = wl1271_ps_elp_wakeup(wl);
2070 if (ret < 0)
2071 goto out_unlock;
2072
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002073 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002074 wl1271_debug(DEBUG_MAC80211,
2075 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002076 ret = -EBUSY;
2077 goto out;
2078 }
2079
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002080 /*
2081 * in some very corner case HW recovery scenarios its possible to
2082 * get here before __wl1271_op_remove_interface is complete, so
2083 * opt out if that is the case.
2084 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002085 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2086 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002087 ret = -EBUSY;
2088 goto out;
2089 }
2090
Eliad Peller83587502011-10-10 10:12:53 +02002091 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002092 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002093 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002094
Eliad Peller252efa42011-10-05 11:56:00 +02002095 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002096 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002097 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2098 ret = -EINVAL;
2099 goto out;
2100 }
Eliad Peller1d095472011-10-10 10:12:49 +02002101
Eliad Peller784f6942011-10-05 11:55:39 +02002102 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002103 * TODO: after the nvs issue will be solved, move this block
2104 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002105 */
Eliad Peller1d095472011-10-10 10:12:49 +02002106 if (wl->state == WL1271_STATE_OFF) {
2107 /*
2108 * we still need this in order to configure the fw
2109 * while uploading the nvs
2110 */
2111 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002112
Eliad Peller1d095472011-10-10 10:12:49 +02002113 booted = wl12xx_init_fw(wl);
2114 if (!booted) {
2115 ret = -EINVAL;
2116 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002117 }
Eliad Peller1d095472011-10-10 10:12:49 +02002118 }
Eliad Peller04e80792011-08-14 13:17:09 +03002119
Eliad Peller1d095472011-10-10 10:12:49 +02002120 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2121 wlvif->bss_type == BSS_TYPE_IBSS) {
2122 /*
2123 * The device role is a special role used for
2124 * rx and tx frames prior to association (as
2125 * the STA role can get packets only from
2126 * its associated bssid)
2127 */
Eliad Peller784f6942011-10-05 11:55:39 +02002128 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002129 WL1271_ROLE_DEVICE,
2130 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002131 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002132 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002133 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002134
Eliad Peller1d095472011-10-10 10:12:49 +02002135 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2136 role_type, &wlvif->role_id);
2137 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002138 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002139
2140 ret = wl1271_init_vif_specific(wl, vif);
2141 if (ret < 0)
2142 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002143
2144 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002145 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002146 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002147
2148 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2149 wl->ap_count++;
2150 else
2151 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002152out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002153 wl1271_ps_elp_sleep(wl);
2154out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002155 mutex_unlock(&wl->mutex);
2156
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002157 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002158 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002159 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002160 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002161
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002162 return ret;
2163}
2164
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002165static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002166 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002167 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002168{
Eliad Peller536129c2011-10-05 11:55:45 +02002169 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002170 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002171
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002172 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002173
Eliad Peller10c8cd02011-10-10 10:13:06 +02002174 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2175 return;
2176
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002177 wl->vif = NULL;
2178
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002179 /* because of hardware recovery, we may get here twice */
2180 if (wl->state != WL1271_STATE_ON)
2181 return;
2182
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002183 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002184
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002185 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002186 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002187 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002188
Eliad Pellerbaf62772011-10-10 10:12:52 +02002189 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2190 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002191 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002192 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002193 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002194 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002195 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002196 }
2197
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002198 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2199 /* disable active roles */
2200 ret = wl1271_ps_elp_wakeup(wl);
2201 if (ret < 0)
2202 goto deinit;
2203
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002204 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2205 wlvif->bss_type == BSS_TYPE_IBSS) {
2206 if (wl12xx_dev_role_started(wlvif))
2207 wl12xx_stop_dev(wl, wlvif);
2208
Eliad Peller7edebf52011-10-05 11:55:52 +02002209 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002210 if (ret < 0)
2211 goto deinit;
2212 }
2213
Eliad Peller0603d892011-10-05 11:55:51 +02002214 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002215 if (ret < 0)
2216 goto deinit;
2217
2218 wl1271_ps_elp_sleep(wl);
2219 }
2220deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002221 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002222 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002223
2224 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2225 wlvif->bss_type == BSS_TYPE_IBSS) {
2226 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2227 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2228 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2229 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2230 } else {
2231 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2232 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2233 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2234 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2235 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2236 wl12xx_free_rate_policy(wl,
2237 &wlvif->ap.ucast_rate_idx[i]);
2238 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002239
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002240 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002241 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002242 if (wl->last_wlvif == wlvif)
2243 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002244 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002245 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002246 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002247 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002248
Eliad Pellera4e41302011-10-11 11:49:15 +02002249 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2250 wl->ap_count--;
2251 else
2252 wl->sta_count--;
2253
Eliad Pellerbaf62772011-10-10 10:12:52 +02002254 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002255 del_timer_sync(&wlvif->rx_streaming_timer);
2256 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2257 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002258 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002259
Eliad Pellerbaf62772011-10-10 10:12:52 +02002260 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002261}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002262
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002263static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2264 struct ieee80211_vif *vif)
2265{
2266 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002267 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002268 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002269
2270 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002271
2272 if (wl->state == WL1271_STATE_OFF ||
2273 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2274 goto out;
2275
Juuso Oikarinen67353292010-11-18 15:19:02 +02002276 /*
2277 * wl->vif can be null here if someone shuts down the interface
2278 * just when hardware recovery has been started.
2279 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002280 wl12xx_for_each_wlvif(wl, iter) {
2281 if (iter != wlvif)
2282 continue;
2283
Eliad Peller536129c2011-10-05 11:55:45 +02002284 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002285 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002286 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002287 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002288out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002289 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002290 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002291}
2292
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002293static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2294 struct ieee80211_vif *vif,
2295 enum nl80211_iftype new_type, bool p2p)
2296{
2297 wl1271_op_remove_interface(hw, vif);
2298
2299 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2300 vif->p2p = p2p;
2301 return wl1271_op_add_interface(hw, vif);
2302}
2303
Eliad Peller87fbcb02011-10-05 11:55:41 +02002304static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2305 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002306{
2307 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002308 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002309
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002310 /*
2311 * One of the side effects of the JOIN command is that is clears
2312 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2313 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002314 * Currently the only valid scenario for JOIN during association
2315 * is on roaming, in which case we will also be given new keys.
2316 * Keep the below message for now, unless it starts bothering
2317 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002318 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002319 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002320 wl1271_info("JOIN while associated.");
2321
2322 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002323 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002324
Eliad Peller227e81e2011-08-14 13:17:26 +03002325 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002326 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002327 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002328 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002329 if (ret < 0)
2330 goto out;
2331
Eliad Pellerba8447f2011-10-10 10:13:00 +02002332 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002333 goto out;
2334
2335 /*
2336 * The join command disable the keep-alive mode, shut down its process,
2337 * and also clear the template config, so we need to reset it all after
2338 * the join. The acx_aid starts the keep-alive process, and the order
2339 * of the commands below is relevant.
2340 */
Eliad Peller0603d892011-10-05 11:55:51 +02002341 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002342 if (ret < 0)
2343 goto out;
2344
Eliad Peller0603d892011-10-05 11:55:51 +02002345 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002346 if (ret < 0)
2347 goto out;
2348
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002349 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002350 if (ret < 0)
2351 goto out;
2352
Eliad Peller0603d892011-10-05 11:55:51 +02002353 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2354 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002355 ACX_KEEP_ALIVE_TPL_VALID);
2356 if (ret < 0)
2357 goto out;
2358
2359out:
2360 return ret;
2361}
2362
Eliad Peller0603d892011-10-05 11:55:51 +02002363static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002364{
2365 int ret;
2366
Eliad Peller52630c52011-10-10 10:13:08 +02002367 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002368 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2369
Shahar Levi6d158ff2011-09-08 13:01:33 +03002370 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002371 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002372 }
2373
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002374 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002375 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002376 if (ret < 0)
2377 goto out;
2378
Oz Krakowskib992c682011-06-26 10:36:02 +03002379 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002380 wlvif->tx_security_last_seq_lsb = 0;
2381 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002382
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002383out:
2384 return ret;
2385}
2386
Eliad Peller87fbcb02011-10-05 11:55:41 +02002387static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002388{
Eliad Peller1b92f152011-10-10 10:13:09 +02002389 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002390 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002391}
2392
Eliad Peller87fbcb02011-10-05 11:55:41 +02002393static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2394 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002395{
2396 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002397 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2398
2399 if (idle == cur_idle)
2400 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002401
2402 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002403 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002404 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002405 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002406 if (ret < 0)
2407 goto out;
2408 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002409 wlvif->rate_set =
2410 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2411 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002412 if (ret < 0)
2413 goto out;
2414 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002415 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002416 ACX_KEEP_ALIVE_TPL_INVALID);
2417 if (ret < 0)
2418 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002419 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002420 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002421 /* The current firmware only supports sched_scan in idle */
2422 if (wl->sched_scanning) {
2423 wl1271_scan_sched_scan_stop(wl);
2424 ieee80211_sched_scan_stopped(wl->hw);
2425 }
2426
Eliad Peller679a6732011-10-11 11:55:44 +02002427 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002428 if (ret < 0)
2429 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002430 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002431 }
2432
2433out:
2434 return ret;
2435}
2436
Eliad Peller9f259c42011-10-10 10:13:12 +02002437static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2438 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002439{
Eliad Peller9f259c42011-10-10 10:13:12 +02002440 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2441 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002442
2443 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2444
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002445 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002446 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002447 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002448 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002449 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002450 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002451 wlvif->band = conf->channel->band;
2452 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002453
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002454 if (!is_ap) {
2455 /*
2456 * FIXME: the mac80211 should really provide a fixed
2457 * rate to use here. for now, just use the smallest
2458 * possible rate for the band as a fixed rate for
2459 * association frames and other control messages.
2460 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002461 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002462 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002463
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002464 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002465 wl1271_tx_min_rate_get(wl,
2466 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002467 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002468 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002469 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002470 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002471
Eliad Pellerba8447f2011-10-10 10:13:00 +02002472 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2473 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002474 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002475 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002476 ret = wl12xx_croc(wl,
2477 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002478 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002479 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002480 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002481 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002482 if (ret < 0)
2483 wl1271_warning("cmd join on channel "
2484 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002485 } else {
2486 /*
2487 * change the ROC channel. do it only if we are
2488 * not idle. otherwise, CROC will be called
2489 * anyway.
2490 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002491 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002492 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002493 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002494 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002495 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002496
Eliad Peller679a6732011-10-11 11:55:44 +02002497 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002498 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002499 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002500 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002501 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002502 }
2503 }
2504
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002505 /*
2506 * if mac80211 changes the PSM mode, make sure the mode is not
2507 * incorrectly changed after the pspoll failure active window.
2508 */
2509 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002510 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002511
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002512 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002513 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2514 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002515
2516 /*
2517 * We enter PSM only if we're already associated.
2518 * If we're not, we'll enter it when joining an SSID,
2519 * through the bss_info_changed() hook.
2520 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002521 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002522 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002523 ret = wl1271_ps_set_mode(wl, wlvif,
2524 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002525 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002526 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002527 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002528 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002529 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002530
Eliad Pellerc29bb002011-10-10 10:13:03 +02002531 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002532
Eliad Pellerc29bb002011-10-10 10:13:03 +02002533 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002534 ret = wl1271_ps_set_mode(wl, wlvif,
2535 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002536 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002537 }
2538
Eliad Peller6bd65022011-10-10 10:13:11 +02002539 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002540 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002541 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002542 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002543
Eliad Peller6bd65022011-10-10 10:13:11 +02002544 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002545 }
2546
Eliad Peller9f259c42011-10-10 10:13:12 +02002547 return 0;
2548}
2549
2550static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2551{
2552 struct wl1271 *wl = hw->priv;
2553 struct wl12xx_vif *wlvif;
2554 struct ieee80211_conf *conf = &hw->conf;
2555 int channel, ret = 0;
2556
2557 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2558
2559 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2560 " changed 0x%x",
2561 channel,
2562 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2563 conf->power_level,
2564 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2565 changed);
2566
2567 /*
2568 * mac80211 will go to idle nearly immediately after transmitting some
2569 * frames, such as the deauth. To make sure those frames reach the air,
2570 * wait here until the TX queue is fully flushed.
2571 */
2572 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2573 (conf->flags & IEEE80211_CONF_IDLE))
2574 wl1271_tx_flush(wl);
2575
2576 mutex_lock(&wl->mutex);
2577
2578 /* we support configuring the channel and band even while off */
2579 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2580 wl->band = conf->channel->band;
2581 wl->channel = channel;
2582 }
2583
2584 if (changed & IEEE80211_CONF_CHANGE_POWER)
2585 wl->power_level = conf->power_level;
2586
2587 if (unlikely(wl->state == WL1271_STATE_OFF))
2588 goto out;
2589
2590 ret = wl1271_ps_elp_wakeup(wl);
2591 if (ret < 0)
2592 goto out;
2593
2594 /* configure each interface */
2595 wl12xx_for_each_wlvif(wl, wlvif) {
2596 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2597 if (ret < 0)
2598 goto out_sleep;
2599 }
2600
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002601out_sleep:
2602 wl1271_ps_elp_sleep(wl);
2603
2604out:
2605 mutex_unlock(&wl->mutex);
2606
2607 return ret;
2608}
2609
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002610struct wl1271_filter_params {
2611 bool enabled;
2612 int mc_list_length;
2613 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2614};
2615
Jiri Pirko22bedad2010-04-01 21:22:57 +00002616static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2617 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002618{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002619 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002620 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002621 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002622
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002623 if (unlikely(wl->state == WL1271_STATE_OFF))
2624 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002625
Juuso Oikarinen74441132009-10-13 12:47:53 +03002626 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002627 if (!fp) {
2628 wl1271_error("Out of memory setting filters.");
2629 return 0;
2630 }
2631
2632 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002633 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002634 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2635 fp->enabled = false;
2636 } else {
2637 fp->enabled = true;
2638 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002639 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002640 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002641 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002642 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002643 }
2644
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002645 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002646}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002647
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002648#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2649 FIF_ALLMULTI | \
2650 FIF_FCSFAIL | \
2651 FIF_BCN_PRBRESP_PROMISC | \
2652 FIF_CONTROL | \
2653 FIF_OTHER_BSS)
2654
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002655static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2656 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002657 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002658{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002659 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002660 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002661 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002662
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002663 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002664
Arik Nemtsov7d057862010-10-16 19:25:35 +02002665 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2666 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002667
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002668 mutex_lock(&wl->mutex);
2669
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002670 *total &= WL1271_SUPPORTED_FILTERS;
2671 changed &= WL1271_SUPPORTED_FILTERS;
2672
2673 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002674 goto out;
2675
Ido Yariva6208652011-03-01 15:14:41 +02002676 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002677 if (ret < 0)
2678 goto out;
2679
Eliad Peller6e8cd332011-10-10 10:13:13 +02002680 wl12xx_for_each_wlvif(wl, wlvif) {
2681 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2682 if (*total & FIF_ALLMULTI)
2683 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2684 false,
2685 NULL, 0);
2686 else if (fp)
2687 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2688 fp->enabled,
2689 fp->mc_list,
2690 fp->mc_list_length);
2691 if (ret < 0)
2692 goto out_sleep;
2693 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002694 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002695
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002696 /*
2697 * the fw doesn't provide an api to configure the filters. instead,
2698 * the filters configuration is based on the active roles / ROC
2699 * state.
2700 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002701
2702out_sleep:
2703 wl1271_ps_elp_sleep(wl);
2704
2705out:
2706 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002707 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002708}
2709
Eliad Peller170d0e62011-10-05 11:56:06 +02002710static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2711 u8 id, u8 key_type, u8 key_size,
2712 const u8 *key, u8 hlid, u32 tx_seq_32,
2713 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002714{
2715 struct wl1271_ap_key *ap_key;
2716 int i;
2717
2718 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2719
2720 if (key_size > MAX_KEY_SIZE)
2721 return -EINVAL;
2722
2723 /*
2724 * Find next free entry in ap_keys. Also check we are not replacing
2725 * an existing key.
2726 */
2727 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002728 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002729 break;
2730
Eliad Peller170d0e62011-10-05 11:56:06 +02002731 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002732 wl1271_warning("trying to record key replacement");
2733 return -EINVAL;
2734 }
2735 }
2736
2737 if (i == MAX_NUM_KEYS)
2738 return -EBUSY;
2739
2740 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2741 if (!ap_key)
2742 return -ENOMEM;
2743
2744 ap_key->id = id;
2745 ap_key->key_type = key_type;
2746 ap_key->key_size = key_size;
2747 memcpy(ap_key->key, key, key_size);
2748 ap_key->hlid = hlid;
2749 ap_key->tx_seq_32 = tx_seq_32;
2750 ap_key->tx_seq_16 = tx_seq_16;
2751
Eliad Peller170d0e62011-10-05 11:56:06 +02002752 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002753 return 0;
2754}
2755
Eliad Peller170d0e62011-10-05 11:56:06 +02002756static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002757{
2758 int i;
2759
2760 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002761 kfree(wlvif->ap.recorded_keys[i]);
2762 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002763 }
2764}
2765
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002766static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002767{
2768 int i, ret = 0;
2769 struct wl1271_ap_key *key;
2770 bool wep_key_added = false;
2771
2772 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002773 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002774 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002775 break;
2776
Eliad Peller170d0e62011-10-05 11:56:06 +02002777 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002778 hlid = key->hlid;
2779 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002780 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002781
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002782 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002783 key->id, key->key_type,
2784 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002785 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002786 key->tx_seq_16);
2787 if (ret < 0)
2788 goto out;
2789
2790 if (key->key_type == KEY_WEP)
2791 wep_key_added = true;
2792 }
2793
2794 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002795 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002796 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002797 if (ret < 0)
2798 goto out;
2799 }
2800
2801out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002802 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002803 return ret;
2804}
2805
Eliad Peller536129c2011-10-05 11:55:45 +02002806static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2807 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002808 u8 key_size, const u8 *key, u32 tx_seq_32,
2809 u16 tx_seq_16, struct ieee80211_sta *sta)
2810{
2811 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002812 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002813
2814 if (is_ap) {
2815 struct wl1271_station *wl_sta;
2816 u8 hlid;
2817
2818 if (sta) {
2819 wl_sta = (struct wl1271_station *)sta->drv_priv;
2820 hlid = wl_sta->hlid;
2821 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002822 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002823 }
2824
Eliad Peller53d40d02011-10-10 10:13:02 +02002825 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002826 /*
2827 * We do not support removing keys after AP shutdown.
2828 * Pretend we do to make mac80211 happy.
2829 */
2830 if (action != KEY_ADD_OR_REPLACE)
2831 return 0;
2832
Eliad Peller170d0e62011-10-05 11:56:06 +02002833 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002834 key_type, key_size,
2835 key, hlid, tx_seq_32,
2836 tx_seq_16);
2837 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002838 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002839 id, key_type, key_size,
2840 key, hlid, tx_seq_32,
2841 tx_seq_16);
2842 }
2843
2844 if (ret < 0)
2845 return ret;
2846 } else {
2847 const u8 *addr;
2848 static const u8 bcast_addr[ETH_ALEN] = {
2849 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2850 };
2851
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002852 /*
2853 * A STA set to GEM cipher requires 2 tx spare blocks.
2854 * Return to default value when GEM cipher key is removed
2855 */
2856 if (key_type == KEY_GEM) {
2857 if (action == KEY_ADD_OR_REPLACE)
2858 wl->tx_spare_blocks = 2;
2859 else if (action == KEY_REMOVE)
2860 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2861 }
2862
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002863 addr = sta ? sta->addr : bcast_addr;
2864
2865 if (is_zero_ether_addr(addr)) {
2866 /* We dont support TX only encryption */
2867 return -EOPNOTSUPP;
2868 }
2869
2870 /* The wl1271 does not allow to remove unicast keys - they
2871 will be cleared automatically on next CMD_JOIN. Ignore the
2872 request silently, as we dont want the mac80211 to emit
2873 an error message. */
2874 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2875 return 0;
2876
Eliad Peller010d3d32011-08-14 13:17:31 +03002877 /* don't remove key if hlid was already deleted */
2878 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002879 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002880 return 0;
2881
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002882 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002883 id, key_type, key_size,
2884 key, addr, tx_seq_32,
2885 tx_seq_16);
2886 if (ret < 0)
2887 return ret;
2888
2889 /* the default WEP key needs to be configured at least once */
2890 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002891 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002892 wlvif->default_key,
2893 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002894 if (ret < 0)
2895 return ret;
2896 }
2897 }
2898
2899 return 0;
2900}
2901
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002902static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2903 struct ieee80211_vif *vif,
2904 struct ieee80211_sta *sta,
2905 struct ieee80211_key_conf *key_conf)
2906{
2907 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002908 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002909 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002910 u32 tx_seq_32 = 0;
2911 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002912 u8 key_type;
2913
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002914 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2915
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002916 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002917 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002918 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002919 key_conf->keylen, key_conf->flags);
2920 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2921
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002922 mutex_lock(&wl->mutex);
2923
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002924 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2925 ret = -EAGAIN;
2926 goto out_unlock;
2927 }
2928
Ido Yariva6208652011-03-01 15:14:41 +02002929 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002930 if (ret < 0)
2931 goto out_unlock;
2932
Johannes Berg97359d12010-08-10 09:46:38 +02002933 switch (key_conf->cipher) {
2934 case WLAN_CIPHER_SUITE_WEP40:
2935 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002936 key_type = KEY_WEP;
2937
2938 key_conf->hw_key_idx = key_conf->keyidx;
2939 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002940 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002941 key_type = KEY_TKIP;
2942
2943 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002944 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2945 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002946 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002947 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002948 key_type = KEY_AES;
2949
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002950 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002951 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2952 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002953 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002954 case WL1271_CIPHER_SUITE_GEM:
2955 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002956 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2957 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002958 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002959 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002960 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002961
2962 ret = -EOPNOTSUPP;
2963 goto out_sleep;
2964 }
2965
2966 switch (cmd) {
2967 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002968 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002969 key_conf->keyidx, key_type,
2970 key_conf->keylen, key_conf->key,
2971 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002972 if (ret < 0) {
2973 wl1271_error("Could not add or replace key");
2974 goto out_sleep;
2975 }
2976 break;
2977
2978 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002979 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002980 key_conf->keyidx, key_type,
2981 key_conf->keylen, key_conf->key,
2982 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002983 if (ret < 0) {
2984 wl1271_error("Could not remove key");
2985 goto out_sleep;
2986 }
2987 break;
2988
2989 default:
2990 wl1271_error("Unsupported key cmd 0x%x", cmd);
2991 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002992 break;
2993 }
2994
2995out_sleep:
2996 wl1271_ps_elp_sleep(wl);
2997
2998out_unlock:
2999 mutex_unlock(&wl->mutex);
3000
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003001 return ret;
3002}
3003
3004static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003005 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003006 struct cfg80211_scan_request *req)
3007{
3008 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003009 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3010
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003011 int ret;
3012 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003013 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003014
3015 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3016
3017 if (req->n_ssids) {
3018 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003019 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003020 }
3021
3022 mutex_lock(&wl->mutex);
3023
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003024 if (wl->state == WL1271_STATE_OFF) {
3025 /*
3026 * We cannot return -EBUSY here because cfg80211 will expect
3027 * a call to ieee80211_scan_completed if we do - in this case
3028 * there won't be any call.
3029 */
3030 ret = -EAGAIN;
3031 goto out;
3032 }
3033
Ido Yariva6208652011-03-01 15:14:41 +02003034 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003035 if (ret < 0)
3036 goto out;
3037
Eliad Peller92e712d2011-12-18 20:25:43 +02003038 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
3039 test_bit(wlvif->role_id, wl->roc_map)) {
3040 /* don't allow scanning right now */
3041 ret = -EBUSY;
3042 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003043 }
3044
Eliad Peller92e712d2011-12-18 20:25:43 +02003045 /* cancel ROC before scanning */
3046 if (wl12xx_dev_role_started(wlvif))
3047 wl12xx_stop_dev(wl, wlvif);
3048
Eliad Peller784f6942011-10-05 11:55:39 +02003049 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003050out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003051 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003052out:
3053 mutex_unlock(&wl->mutex);
3054
3055 return ret;
3056}
3057
Eliad Peller73ecce32011-06-27 13:06:45 +03003058static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3059 struct ieee80211_vif *vif)
3060{
3061 struct wl1271 *wl = hw->priv;
3062 int ret;
3063
3064 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3065
3066 mutex_lock(&wl->mutex);
3067
3068 if (wl->state == WL1271_STATE_OFF)
3069 goto out;
3070
3071 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3072 goto out;
3073
3074 ret = wl1271_ps_elp_wakeup(wl);
3075 if (ret < 0)
3076 goto out;
3077
3078 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3079 ret = wl1271_scan_stop(wl);
3080 if (ret < 0)
3081 goto out_sleep;
3082 }
3083 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3084 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003085 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003086 wl->scan.req = NULL;
3087 ieee80211_scan_completed(wl->hw, true);
3088
3089out_sleep:
3090 wl1271_ps_elp_sleep(wl);
3091out:
3092 mutex_unlock(&wl->mutex);
3093
3094 cancel_delayed_work_sync(&wl->scan_complete_work);
3095}
3096
Luciano Coelho33c2c062011-05-10 14:46:02 +03003097static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3098 struct ieee80211_vif *vif,
3099 struct cfg80211_sched_scan_request *req,
3100 struct ieee80211_sched_scan_ies *ies)
3101{
3102 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003103 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003104 int ret;
3105
3106 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3107
3108 mutex_lock(&wl->mutex);
3109
3110 ret = wl1271_ps_elp_wakeup(wl);
3111 if (ret < 0)
3112 goto out;
3113
Eliad Peller536129c2011-10-05 11:55:45 +02003114 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003115 if (ret < 0)
3116 goto out_sleep;
3117
Eliad Peller536129c2011-10-05 11:55:45 +02003118 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003119 if (ret < 0)
3120 goto out_sleep;
3121
3122 wl->sched_scanning = true;
3123
3124out_sleep:
3125 wl1271_ps_elp_sleep(wl);
3126out:
3127 mutex_unlock(&wl->mutex);
3128 return ret;
3129}
3130
3131static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3132 struct ieee80211_vif *vif)
3133{
3134 struct wl1271 *wl = hw->priv;
3135 int ret;
3136
3137 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3138
3139 mutex_lock(&wl->mutex);
3140
3141 ret = wl1271_ps_elp_wakeup(wl);
3142 if (ret < 0)
3143 goto out;
3144
3145 wl1271_scan_sched_scan_stop(wl);
3146
3147 wl1271_ps_elp_sleep(wl);
3148out:
3149 mutex_unlock(&wl->mutex);
3150}
3151
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003152static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3153{
3154 struct wl1271 *wl = hw->priv;
3155 int ret = 0;
3156
3157 mutex_lock(&wl->mutex);
3158
3159 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3160 ret = -EAGAIN;
3161 goto out;
3162 }
3163
Ido Yariva6208652011-03-01 15:14:41 +02003164 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003165 if (ret < 0)
3166 goto out;
3167
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003168 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003169 if (ret < 0)
3170 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3171
3172 wl1271_ps_elp_sleep(wl);
3173
3174out:
3175 mutex_unlock(&wl->mutex);
3176
3177 return ret;
3178}
3179
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003180static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3181{
3182 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003183 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003184 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003185
3186 mutex_lock(&wl->mutex);
3187
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003188 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3189 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003190 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003191 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003192
Ido Yariva6208652011-03-01 15:14:41 +02003193 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003194 if (ret < 0)
3195 goto out;
3196
Eliad Peller6e8cd332011-10-10 10:13:13 +02003197 wl12xx_for_each_wlvif(wl, wlvif) {
3198 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3199 if (ret < 0)
3200 wl1271_warning("set rts threshold failed: %d", ret);
3201 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003202 wl1271_ps_elp_sleep(wl);
3203
3204out:
3205 mutex_unlock(&wl->mutex);
3206
3207 return ret;
3208}
3209
Eliad Peller1fe9f162011-10-05 11:55:48 +02003210static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003211 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003212{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003213 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003214 u8 ssid_len;
3215 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3216 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003217
Eliad Peller889cb362011-05-01 09:56:45 +03003218 if (!ptr) {
3219 wl1271_error("No SSID in IEs!");
3220 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003221 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003222
Eliad Peller889cb362011-05-01 09:56:45 +03003223 ssid_len = ptr[1];
3224 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3225 wl1271_error("SSID is too long!");
3226 return -EINVAL;
3227 }
3228
Eliad Peller1fe9f162011-10-05 11:55:48 +02003229 wlvif->ssid_len = ssid_len;
3230 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003231 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003232}
3233
Eliad Pellerd48055d2011-09-15 12:07:04 +03003234static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3235{
3236 int len;
3237 const u8 *next, *end = skb->data + skb->len;
3238 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3239 skb->len - ieoffset);
3240 if (!ie)
3241 return;
3242 len = ie[1] + 2;
3243 next = ie + len;
3244 memmove(ie, next, end - next);
3245 skb_trim(skb, skb->len - len);
3246}
3247
Eliad Peller26b4bf22011-09-15 12:07:05 +03003248static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3249 unsigned int oui, u8 oui_type,
3250 int ieoffset)
3251{
3252 int len;
3253 const u8 *next, *end = skb->data + skb->len;
3254 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3255 skb->data + ieoffset,
3256 skb->len - ieoffset);
3257 if (!ie)
3258 return;
3259 len = ie[1] + 2;
3260 next = ie + len;
3261 memmove(ie, next, end - next);
3262 skb_trim(skb, skb->len - len);
3263}
3264
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003265static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3266 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003267{
3268 struct sk_buff *skb;
3269 int ret;
3270
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003271 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003272 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003273 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003274
3275 ret = wl1271_cmd_template_set(wl,
3276 CMD_TEMPL_AP_PROBE_RESPONSE,
3277 skb->data,
3278 skb->len, 0,
3279 rates);
3280
3281 dev_kfree_skb(skb);
3282 return ret;
3283}
3284
3285static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3286 struct ieee80211_vif *vif,
3287 u8 *probe_rsp_data,
3288 size_t probe_rsp_len,
3289 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003290{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003291 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3292 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003293 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3294 int ssid_ie_offset, ie_offset, templ_len;
3295 const u8 *ptr;
3296
3297 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003298 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003299 return wl1271_cmd_template_set(wl,
3300 CMD_TEMPL_AP_PROBE_RESPONSE,
3301 probe_rsp_data,
3302 probe_rsp_len, 0,
3303 rates);
3304
3305 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3306 wl1271_error("probe_rsp template too big");
3307 return -EINVAL;
3308 }
3309
3310 /* start searching from IE offset */
3311 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3312
3313 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3314 probe_rsp_len - ie_offset);
3315 if (!ptr) {
3316 wl1271_error("No SSID in beacon!");
3317 return -EINVAL;
3318 }
3319
3320 ssid_ie_offset = ptr - probe_rsp_data;
3321 ptr += (ptr[1] + 2);
3322
3323 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3324
3325 /* insert SSID from bss_conf */
3326 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3327 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3328 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3329 bss_conf->ssid, bss_conf->ssid_len);
3330 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3331
3332 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3333 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3334 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3335
3336 return wl1271_cmd_template_set(wl,
3337 CMD_TEMPL_AP_PROBE_RESPONSE,
3338 probe_rsp_templ,
3339 templ_len, 0,
3340 rates);
3341}
3342
Arik Nemtsove78a2872010-10-16 19:07:21 +02003343static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003344 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003345 struct ieee80211_bss_conf *bss_conf,
3346 u32 changed)
3347{
Eliad Peller0603d892011-10-05 11:55:51 +02003348 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003349 int ret = 0;
3350
3351 if (changed & BSS_CHANGED_ERP_SLOT) {
3352 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003353 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003354 else
Eliad Peller0603d892011-10-05 11:55:51 +02003355 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003356 if (ret < 0) {
3357 wl1271_warning("Set slot time failed %d", ret);
3358 goto out;
3359 }
3360 }
3361
3362 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3363 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003364 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003365 else
Eliad Peller0603d892011-10-05 11:55:51 +02003366 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003367 }
3368
3369 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3370 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003371 ret = wl1271_acx_cts_protect(wl, wlvif,
3372 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003373 else
Eliad Peller0603d892011-10-05 11:55:51 +02003374 ret = wl1271_acx_cts_protect(wl, wlvif,
3375 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003376 if (ret < 0) {
3377 wl1271_warning("Set ctsprotect failed %d", ret);
3378 goto out;
3379 }
3380 }
3381
3382out:
3383 return ret;
3384}
3385
3386static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3387 struct ieee80211_vif *vif,
3388 struct ieee80211_bss_conf *bss_conf,
3389 u32 changed)
3390{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003391 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003392 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003393 int ret = 0;
3394
3395 if ((changed & BSS_CHANGED_BEACON_INT)) {
3396 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3397 bss_conf->beacon_int);
3398
Eliad Peller6a899792011-10-05 11:55:58 +02003399 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003400 }
3401
Arik Nemtsov560f0022011-11-08 18:46:54 +02003402 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3403 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003404 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3405 wl1271_debug(DEBUG_AP, "probe response updated");
3406 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3407 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003408 }
3409
Arik Nemtsove78a2872010-10-16 19:07:21 +02003410 if ((changed & BSS_CHANGED_BEACON)) {
3411 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003412 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003413 int ieoffset = offsetof(struct ieee80211_mgmt,
3414 u.beacon.variable);
3415 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3416 u16 tmpl_id;
3417
Arik Nemtsov560f0022011-11-08 18:46:54 +02003418 if (!beacon) {
3419 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003420 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003421 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003422
3423 wl1271_debug(DEBUG_MASTER, "beacon updated");
3424
Eliad Peller1fe9f162011-10-05 11:55:48 +02003425 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003426 if (ret < 0) {
3427 dev_kfree_skb(beacon);
3428 goto out;
3429 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003430 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003431 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3432 CMD_TEMPL_BEACON;
3433 ret = wl1271_cmd_template_set(wl, tmpl_id,
3434 beacon->data,
3435 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003436 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003437 if (ret < 0) {
3438 dev_kfree_skb(beacon);
3439 goto out;
3440 }
3441
Arik Nemtsov560f0022011-11-08 18:46:54 +02003442 /*
3443 * In case we already have a probe-resp beacon set explicitly
3444 * by usermode, don't use the beacon data.
3445 */
3446 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3447 goto end_bcn;
3448
Eliad Pellerd48055d2011-09-15 12:07:04 +03003449 /* remove TIM ie from probe response */
3450 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3451
Eliad Peller26b4bf22011-09-15 12:07:05 +03003452 /*
3453 * remove p2p ie from probe response.
3454 * the fw reponds to probe requests that don't include
3455 * the p2p ie. probe requests with p2p ie will be passed,
3456 * and will be responded by the supplicant (the spec
3457 * forbids including the p2p ie when responding to probe
3458 * requests that didn't include it).
3459 */
3460 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3461 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3462
Arik Nemtsove78a2872010-10-16 19:07:21 +02003463 hdr = (struct ieee80211_hdr *) beacon->data;
3464 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3465 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003466 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003467 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003468 beacon->data,
3469 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003470 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003471 else
3472 ret = wl1271_cmd_template_set(wl,
3473 CMD_TEMPL_PROBE_RESPONSE,
3474 beacon->data,
3475 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003476 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003477end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003478 dev_kfree_skb(beacon);
3479 if (ret < 0)
3480 goto out;
3481 }
3482
3483out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003484 if (ret != 0)
3485 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003486 return ret;
3487}
3488
3489/* AP mode changes */
3490static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003491 struct ieee80211_vif *vif,
3492 struct ieee80211_bss_conf *bss_conf,
3493 u32 changed)
3494{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003495 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003496 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003497
Arik Nemtsove78a2872010-10-16 19:07:21 +02003498 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3499 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003500
Eliad Peller87fbcb02011-10-05 11:55:41 +02003501 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003502 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003503 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003504 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003505
Eliad Peller87fbcb02011-10-05 11:55:41 +02003506 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003507 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003508 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003509 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003510 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003511
Eliad Peller784f6942011-10-05 11:55:39 +02003512 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003513 if (ret < 0)
3514 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003515 }
3516
Arik Nemtsove78a2872010-10-16 19:07:21 +02003517 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3518 if (ret < 0)
3519 goto out;
3520
3521 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3522 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003523 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003524 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003525 if (ret < 0)
3526 goto out;
3527
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003528 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003529 if (ret < 0)
3530 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003531
Eliad Peller53d40d02011-10-10 10:13:02 +02003532 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003533 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003534 }
3535 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003536 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003537 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003538 if (ret < 0)
3539 goto out;
3540
Eliad Peller53d40d02011-10-10 10:13:02 +02003541 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003542 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3543 &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 Peller536129c2011-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 Peller679a6732011-10-11 11:55:44 +02003599 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003600 }
3601 }
3602 }
3603
3604 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003605 do_join = true;
3606
3607 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003608 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003609 do_join = true;
3610
Eliad Peller227e81e2011-08-14 13:17:26 +03003611 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003612 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3613 bss_conf->enable_beacon ? "enabled" : "disabled");
3614
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003615 do_join = true;
3616 }
3617
Eliad Pellerc31e4942011-10-23 08:21:55 +02003618 if (changed & BSS_CHANGED_IDLE) {
3619 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3620 if (ret < 0)
3621 wl1271_warning("idle mode change failed %d", ret);
3622 }
3623
Arik Nemtsove78a2872010-10-16 19:07:21 +02003624 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003625 bool enable = false;
3626 if (bss_conf->cqm_rssi_thold)
3627 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003628 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003629 bss_conf->cqm_rssi_thold,
3630 bss_conf->cqm_rssi_hyst);
3631 if (ret < 0)
3632 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003633 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003634 }
3635
Eliad Pellercdf09492011-10-05 11:55:44 +02003636 if (changed & BSS_CHANGED_BSSID)
3637 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003638 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003639 if (ret < 0)
3640 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003641
Eliad Peller784f6942011-10-05 11:55:39 +02003642 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003643 if (ret < 0)
3644 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003645
Eliad Pellerfa287b82010-12-26 09:27:50 +01003646 /* Need to update the BSSID (for filtering etc) */
3647 do_join = true;
3648 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003649
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003650 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3651 rcu_read_lock();
3652 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3653 if (!sta)
3654 goto sta_not_found;
3655
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003656 /* save the supp_rates of the ap */
3657 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3658 if (sta->ht_cap.ht_supported)
3659 sta_rate_set |=
3660 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003661 sta_ht_cap = sta->ht_cap;
3662 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003663
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003664sta_not_found:
3665 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003666 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003667
Arik Nemtsove78a2872010-10-16 19:07:21 +02003668 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003669 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003670 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003671 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003672 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003673 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003674
Eliad Peller74ec8392011-10-05 11:56:02 +02003675 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003676
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003677 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003678 * use basic rates from AP, and determine lowest rate
3679 * to use with control frames.
3680 */
3681 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003682 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003683 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003684 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003685 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003686 wl1271_tx_min_rate_get(wl,
3687 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003688 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003689 wlvif->rate_set =
3690 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003691 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003692 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003693 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003694 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003695 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003696
3697 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003698 * with wl1271, we don't need to update the
3699 * beacon_int and dtim_period, because the firmware
3700 * updates it by itself when the first beacon is
3701 * received after a join.
3702 */
Eliad Peller6840e372011-10-05 11:55:50 +02003703 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003704 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003705 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003706
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003707 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003708 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003709 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003710 dev_kfree_skb(wlvif->probereq);
3711 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003712 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003713 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003714 ieoffset = offsetof(struct ieee80211_mgmt,
3715 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003716 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003717
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003718 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003719 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003720 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003721 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003722 } else {
3723 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003724 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003725 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3726 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003727 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003728 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3729 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003730 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003731
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003732 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003733 dev_kfree_skb(wlvif->probereq);
3734 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003735
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003736 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003737 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003738
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003739 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003740 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003741 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003742 wl1271_tx_min_rate_get(wl,
3743 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003744 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003745 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003746 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003747
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003748 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003749 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003750
3751 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003752 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003753 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003754 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003755
3756 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003757 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003758 u32 conf_flags = wl->hw->conf.flags;
3759 /*
3760 * we might have to disable roc, if there was
3761 * no IF_OPER_UP notification.
3762 */
3763 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003764 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003765 if (ret < 0)
3766 goto out;
3767 }
3768 /*
3769 * (we also need to disable roc in case of
3770 * roaming on the same channel. until we will
3771 * have a better flow...)
3772 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003773 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3774 ret = wl12xx_croc(wl,
3775 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003776 if (ret < 0)
3777 goto out;
3778 }
3779
Eliad Peller0603d892011-10-05 11:55:51 +02003780 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003781 if (!(conf_flags & IEEE80211_CONF_IDLE))
3782 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003783 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003784 }
3785 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003786
Eliad Pellerd192d262011-05-24 14:33:08 +03003787 if (changed & BSS_CHANGED_IBSS) {
3788 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3789 bss_conf->ibss_joined);
3790
3791 if (bss_conf->ibss_joined) {
3792 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003793 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003794 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003795 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003796 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003797 wl1271_tx_min_rate_get(wl,
3798 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003799
Shahar Levi06b660e2011-09-05 13:54:36 +03003800 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003801 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3802 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003803 if (ret < 0)
3804 goto out;
3805 }
3806 }
3807
Eliad Peller0603d892011-10-05 11:55:51 +02003808 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003809 if (ret < 0)
3810 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003811
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003812 if (changed & BSS_CHANGED_ARP_FILTER) {
3813 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003814 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003815
Eliad Pellerc5312772010-12-09 11:31:27 +02003816 if (bss_conf->arp_addr_cnt == 1 &&
3817 bss_conf->arp_filter_enabled) {
3818 /*
3819 * The template should have been configured only upon
3820 * association. however, it seems that the correct ip
3821 * isn't being set (when sending), so we have to
3822 * reconfigure the template upon every ip change.
3823 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003824 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003825 if (ret < 0) {
3826 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003827 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003828 }
3829
Eliad Peller0603d892011-10-05 11:55:51 +02003830 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003831 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003832 addr);
3833 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003834 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003835
3836 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003837 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003838 }
3839
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003840 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003841 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003842 if (ret < 0) {
3843 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003844 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003845 }
Eliad Peller251c1772011-08-14 13:17:17 +03003846
3847 /* ROC until connected (after EAPOL exchange) */
3848 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003849 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003850 if (ret < 0)
3851 goto out;
3852
Eliad Pellerba8447f2011-10-10 10:13:00 +02003853 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003854 ieee80211_get_operstate(vif));
3855 }
3856 /*
3857 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003858 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003859 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003860 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003861 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003862 if (ret < 0)
3863 goto out;
3864 }
Eliad Peller05dba352011-08-23 16:37:01 +03003865
3866 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003867 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3868 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003869 enum wl1271_cmd_ps_mode mode;
3870
3871 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003872 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003873 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003874 true);
3875 if (ret < 0)
3876 goto out;
3877 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003878 }
3879
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003880 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003881 if (sta_exists) {
3882 if ((changed & BSS_CHANGED_HT) &&
3883 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003884 ret = wl1271_acx_set_ht_capabilities(wl,
3885 &sta_ht_cap,
3886 true,
Eliad Peller154da672011-10-05 11:55:53 +02003887 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003888 if (ret < 0) {
3889 wl1271_warning("Set ht cap true failed %d",
3890 ret);
3891 goto out;
3892 }
3893 }
3894 /* handle new association without HT and disassociation */
3895 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003896 ret = wl1271_acx_set_ht_capabilities(wl,
3897 &sta_ht_cap,
3898 false,
Eliad Peller154da672011-10-05 11:55:53 +02003899 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003900 if (ret < 0) {
3901 wl1271_warning("Set ht cap false failed %d",
3902 ret);
3903 goto out;
3904 }
3905 }
3906 }
3907
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003908 /* Handle HT information change. Done after join. */
3909 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003910 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003911 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003912 bss_conf->ht_operation_mode);
3913 if (ret < 0) {
3914 wl1271_warning("Set ht information failed %d", ret);
3915 goto out;
3916 }
3917 }
3918
Arik Nemtsove78a2872010-10-16 19:07:21 +02003919out:
3920 return;
3921}
3922
3923static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3924 struct ieee80211_vif *vif,
3925 struct ieee80211_bss_conf *bss_conf,
3926 u32 changed)
3927{
3928 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003929 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3930 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003931 int ret;
3932
3933 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3934 (int)changed);
3935
3936 mutex_lock(&wl->mutex);
3937
3938 if (unlikely(wl->state == WL1271_STATE_OFF))
3939 goto out;
3940
Eliad Peller10c8cd02011-10-10 10:13:06 +02003941 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3942 goto out;
3943
Ido Yariva6208652011-03-01 15:14:41 +02003944 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003945 if (ret < 0)
3946 goto out;
3947
3948 if (is_ap)
3949 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3950 else
3951 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3952
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003953 wl1271_ps_elp_sleep(wl);
3954
3955out:
3956 mutex_unlock(&wl->mutex);
3957}
3958
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003959static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3960 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003961 const struct ieee80211_tx_queue_params *params)
3962{
3963 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003964 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003965 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003966 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003967
3968 mutex_lock(&wl->mutex);
3969
3970 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3971
Kalle Valo4695dc92010-03-18 12:26:38 +02003972 if (params->uapsd)
3973 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3974 else
3975 ps_scheme = CONF_PS_SCHEME_LEGACY;
3976
Eliad Peller5b37ddf2011-12-18 20:25:40 +02003977 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003978 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003979
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003980 ret = wl1271_ps_elp_wakeup(wl);
3981 if (ret < 0)
3982 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003983
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003984 /*
3985 * the txop is confed in units of 32us by the mac80211,
3986 * we need us
3987 */
Eliad Peller0603d892011-10-05 11:55:51 +02003988 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003989 params->cw_min, params->cw_max,
3990 params->aifs, params->txop << 5);
3991 if (ret < 0)
3992 goto out_sleep;
3993
Eliad Peller0603d892011-10-05 11:55:51 +02003994 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003995 CONF_CHANNEL_TYPE_EDCF,
3996 wl1271_tx_get_queue(queue),
3997 ps_scheme, CONF_ACK_POLICY_LEGACY,
3998 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003999
4000out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004001 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004002
4003out:
4004 mutex_unlock(&wl->mutex);
4005
4006 return ret;
4007}
4008
Eliad Peller37a41b42011-09-21 14:06:11 +03004009static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4010 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004011{
4012
4013 struct wl1271 *wl = hw->priv;
4014 u64 mactime = ULLONG_MAX;
4015 int ret;
4016
4017 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4018
4019 mutex_lock(&wl->mutex);
4020
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004021 if (unlikely(wl->state == WL1271_STATE_OFF))
4022 goto out;
4023
Ido Yariva6208652011-03-01 15:14:41 +02004024 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004025 if (ret < 0)
4026 goto out;
4027
4028 ret = wl1271_acx_tsf_info(wl, &mactime);
4029 if (ret < 0)
4030 goto out_sleep;
4031
4032out_sleep:
4033 wl1271_ps_elp_sleep(wl);
4034
4035out:
4036 mutex_unlock(&wl->mutex);
4037 return mactime;
4038}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004039
John W. Linvilleece550d2010-07-28 16:41:06 -04004040static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4041 struct survey_info *survey)
4042{
4043 struct wl1271 *wl = hw->priv;
4044 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004045
John W. Linvilleece550d2010-07-28 16:41:06 -04004046 if (idx != 0)
4047 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004048
John W. Linvilleece550d2010-07-28 16:41:06 -04004049 survey->channel = conf->channel;
4050 survey->filled = SURVEY_INFO_NOISE_DBM;
4051 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004052
John W. Linvilleece550d2010-07-28 16:41:06 -04004053 return 0;
4054}
4055
Arik Nemtsov409622e2011-02-23 00:22:29 +02004056static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004057 struct wl12xx_vif *wlvif,
4058 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004059{
4060 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004061 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004062
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004063
4064 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004065 wl1271_warning("could not allocate HLID - too much stations");
4066 return -EBUSY;
4067 }
4068
4069 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004070 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4071 if (ret < 0) {
4072 wl1271_warning("could not allocate HLID - too many links");
4073 return -EBUSY;
4074 }
4075
4076 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004077 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004078 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004079 return 0;
4080}
4081
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004082void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004083{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004084 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004085 return;
4086
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004087 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004088 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004089 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004090 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004091 __clear_bit(hlid, &wl->ap_ps_map);
4092 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004093 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004094 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004095}
4096
4097static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4098 struct ieee80211_vif *vif,
4099 struct ieee80211_sta *sta)
4100{
4101 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004102 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004103 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004104 int ret = 0;
4105 u8 hlid;
4106
4107 mutex_lock(&wl->mutex);
4108
4109 if (unlikely(wl->state == WL1271_STATE_OFF))
4110 goto out;
4111
Eliad Peller536129c2011-10-05 11:55:45 +02004112 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004113 goto out;
4114
4115 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4116
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004117 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004118 if (ret < 0)
4119 goto out;
4120
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004121 wl_sta = (struct wl1271_station *)sta->drv_priv;
4122 hlid = wl_sta->hlid;
4123
Ido Yariva6208652011-03-01 15:14:41 +02004124 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004125 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004126 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004127
Eliad Peller1b92f152011-10-10 10:13:09 +02004128 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004129 if (ret < 0)
4130 goto out_sleep;
4131
Eliad Pellerb67476e2011-08-14 13:17:23 +03004132 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4133 if (ret < 0)
4134 goto out_sleep;
4135
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004136 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4137 if (ret < 0)
4138 goto out_sleep;
4139
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004140out_sleep:
4141 wl1271_ps_elp_sleep(wl);
4142
Arik Nemtsov409622e2011-02-23 00:22:29 +02004143out_free_sta:
4144 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004145 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004146
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004147out:
4148 mutex_unlock(&wl->mutex);
4149 return ret;
4150}
4151
4152static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4153 struct ieee80211_vif *vif,
4154 struct ieee80211_sta *sta)
4155{
4156 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004157 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004158 struct wl1271_station *wl_sta;
4159 int ret = 0, id;
4160
4161 mutex_lock(&wl->mutex);
4162
4163 if (unlikely(wl->state == WL1271_STATE_OFF))
4164 goto out;
4165
Eliad Peller536129c2011-10-05 11:55:45 +02004166 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004167 goto out;
4168
4169 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4170
4171 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004172 id = wl_sta->hlid;
4173 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004174 goto out;
4175
Ido Yariva6208652011-03-01 15:14:41 +02004176 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004177 if (ret < 0)
4178 goto out;
4179
Eliad Pellerc690ec82011-08-14 13:17:07 +03004180 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004181 if (ret < 0)
4182 goto out_sleep;
4183
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004184 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004185
4186out_sleep:
4187 wl1271_ps_elp_sleep(wl);
4188
4189out:
4190 mutex_unlock(&wl->mutex);
4191 return ret;
4192}
4193
Luciano Coelho4623ec72011-03-21 19:26:41 +02004194static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4195 struct ieee80211_vif *vif,
4196 enum ieee80211_ampdu_mlme_action action,
4197 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4198 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004199{
4200 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004201 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004202 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004203 u8 hlid, *ba_bitmap;
4204
4205 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4206 tid);
4207
4208 /* sanity check - the fields in FW are only 8bits wide */
4209 if (WARN_ON(tid > 0xFF))
4210 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004211
4212 mutex_lock(&wl->mutex);
4213
4214 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4215 ret = -EAGAIN;
4216 goto out;
4217 }
4218
Eliad Peller536129c2011-10-05 11:55:45 +02004219 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004220 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004221 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004222 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004223 struct wl1271_station *wl_sta;
4224
4225 wl_sta = (struct wl1271_station *)sta->drv_priv;
4226 hlid = wl_sta->hlid;
4227 ba_bitmap = &wl->links[hlid].ba_bitmap;
4228 } else {
4229 ret = -EINVAL;
4230 goto out;
4231 }
4232
Ido Yariva6208652011-03-01 15:14:41 +02004233 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004234 if (ret < 0)
4235 goto out;
4236
Shahar Levi70559a02011-05-22 16:10:22 +03004237 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4238 tid, action);
4239
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004240 switch (action) {
4241 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004242 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004243 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004244 break;
4245 }
4246
4247 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4248 ret = -EBUSY;
4249 wl1271_error("exceeded max RX BA sessions");
4250 break;
4251 }
4252
4253 if (*ba_bitmap & BIT(tid)) {
4254 ret = -EINVAL;
4255 wl1271_error("cannot enable RX BA session on active "
4256 "tid: %d", tid);
4257 break;
4258 }
4259
4260 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4261 hlid);
4262 if (!ret) {
4263 *ba_bitmap |= BIT(tid);
4264 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004265 }
4266 break;
4267
4268 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004269 if (!(*ba_bitmap & BIT(tid))) {
4270 ret = -EINVAL;
4271 wl1271_error("no active RX BA session on tid: %d",
4272 tid);
4273 break;
4274 }
4275
4276 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4277 hlid);
4278 if (!ret) {
4279 *ba_bitmap &= ~BIT(tid);
4280 wl->ba_rx_session_count--;
4281 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004282 break;
4283
4284 /*
4285 * The BA initiator session management in FW independently.
4286 * Falling break here on purpose for all TX APDU commands.
4287 */
4288 case IEEE80211_AMPDU_TX_START:
4289 case IEEE80211_AMPDU_TX_STOP:
4290 case IEEE80211_AMPDU_TX_OPERATIONAL:
4291 ret = -EINVAL;
4292 break;
4293
4294 default:
4295 wl1271_error("Incorrect ampdu action id=%x\n", action);
4296 ret = -EINVAL;
4297 }
4298
4299 wl1271_ps_elp_sleep(wl);
4300
4301out:
4302 mutex_unlock(&wl->mutex);
4303
4304 return ret;
4305}
4306
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004307static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4308 struct ieee80211_vif *vif,
4309 const struct cfg80211_bitrate_mask *mask)
4310{
Eliad Peller83587502011-10-10 10:12:53 +02004311 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004312 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004313 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004314
4315 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4316 mask->control[NL80211_BAND_2GHZ].legacy,
4317 mask->control[NL80211_BAND_5GHZ].legacy);
4318
4319 mutex_lock(&wl->mutex);
4320
4321 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004322 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004323 wl1271_tx_enabled_rates_get(wl,
4324 mask->control[i].legacy,
4325 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004326
4327 if (unlikely(wl->state == WL1271_STATE_OFF))
4328 goto out;
4329
4330 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4331 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4332
4333 ret = wl1271_ps_elp_wakeup(wl);
4334 if (ret < 0)
4335 goto out;
4336
4337 wl1271_set_band_rate(wl, wlvif);
4338 wlvif->basic_rate =
4339 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4340 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4341
4342 wl1271_ps_elp_sleep(wl);
4343 }
4344out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004345 mutex_unlock(&wl->mutex);
4346
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004347 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004348}
4349
Shahar Levi6d158ff2011-09-08 13:01:33 +03004350static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4351 struct ieee80211_channel_switch *ch_switch)
4352{
4353 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004354 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004355 int ret;
4356
4357 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4358
4359 mutex_lock(&wl->mutex);
4360
4361 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004362 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4363 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4364 ieee80211_chswitch_done(vif, false);
4365 }
4366 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004367 }
4368
4369 ret = wl1271_ps_elp_wakeup(wl);
4370 if (ret < 0)
4371 goto out;
4372
Eliad Peller52630c52011-10-10 10:13:08 +02004373 /* TODO: change mac80211 to pass vif as param */
4374 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4375 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004376
Eliad Peller52630c52011-10-10 10:13:08 +02004377 if (!ret)
4378 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4379 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004380
4381 wl1271_ps_elp_sleep(wl);
4382
4383out:
4384 mutex_unlock(&wl->mutex);
4385}
4386
Arik Nemtsov33437892011-04-26 23:35:39 +03004387static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4388{
4389 struct wl1271 *wl = hw->priv;
4390 bool ret = false;
4391
4392 mutex_lock(&wl->mutex);
4393
4394 if (unlikely(wl->state == WL1271_STATE_OFF))
4395 goto out;
4396
4397 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004398 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004399out:
4400 mutex_unlock(&wl->mutex);
4401
4402 return ret;
4403}
4404
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004405/* can't be const, mac80211 writes to this */
4406static struct ieee80211_rate wl1271_rates[] = {
4407 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004408 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4409 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004410 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004411 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4412 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004413 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4414 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004415 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4416 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004417 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4418 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004419 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4420 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004421 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4422 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004423 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4424 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004425 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004426 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4427 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004428 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004429 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4430 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004431 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004432 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4433 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004434 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004435 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4436 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004437 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004438 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4439 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004440 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004441 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4442 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004443 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004444 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4445 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004446};
4447
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004448/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004449static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004450 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004451 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004452 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4453 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4454 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004455 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004456 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4457 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4458 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004459 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004460 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4461 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4462 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004463 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004464};
4465
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004466/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004467static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004468 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004469 7, /* CONF_HW_RXTX_RATE_MCS7 */
4470 6, /* CONF_HW_RXTX_RATE_MCS6 */
4471 5, /* CONF_HW_RXTX_RATE_MCS5 */
4472 4, /* CONF_HW_RXTX_RATE_MCS4 */
4473 3, /* CONF_HW_RXTX_RATE_MCS3 */
4474 2, /* CONF_HW_RXTX_RATE_MCS2 */
4475 1, /* CONF_HW_RXTX_RATE_MCS1 */
4476 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004477
4478 11, /* CONF_HW_RXTX_RATE_54 */
4479 10, /* CONF_HW_RXTX_RATE_48 */
4480 9, /* CONF_HW_RXTX_RATE_36 */
4481 8, /* CONF_HW_RXTX_RATE_24 */
4482
4483 /* TI-specific rate */
4484 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4485
4486 7, /* CONF_HW_RXTX_RATE_18 */
4487 6, /* CONF_HW_RXTX_RATE_12 */
4488 3, /* CONF_HW_RXTX_RATE_11 */
4489 5, /* CONF_HW_RXTX_RATE_9 */
4490 4, /* CONF_HW_RXTX_RATE_6 */
4491 2, /* CONF_HW_RXTX_RATE_5_5 */
4492 1, /* CONF_HW_RXTX_RATE_2 */
4493 0 /* CONF_HW_RXTX_RATE_1 */
4494};
4495
Shahar Levie8b03a22010-10-13 16:09:39 +02004496/* 11n STA capabilities */
4497#define HW_RX_HIGHEST_RATE 72
4498
Shahar Levi00d20102010-11-08 11:20:10 +00004499#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004500 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4501 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004502 .ht_supported = true, \
4503 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4504 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4505 .mcs = { \
4506 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4507 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4508 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4509 }, \
4510}
4511
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004512/* can't be const, mac80211 writes to this */
4513static struct ieee80211_supported_band wl1271_band_2ghz = {
4514 .channels = wl1271_channels,
4515 .n_channels = ARRAY_SIZE(wl1271_channels),
4516 .bitrates = wl1271_rates,
4517 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004518 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004519};
4520
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004521/* 5 GHz data rates for WL1273 */
4522static struct ieee80211_rate wl1271_rates_5ghz[] = {
4523 { .bitrate = 60,
4524 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4525 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4526 { .bitrate = 90,
4527 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4528 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4529 { .bitrate = 120,
4530 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4531 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4532 { .bitrate = 180,
4533 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4534 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4535 { .bitrate = 240,
4536 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4537 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4538 { .bitrate = 360,
4539 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4540 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4541 { .bitrate = 480,
4542 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4543 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4544 { .bitrate = 540,
4545 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4546 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4547};
4548
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004549/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004550static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004551 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4552 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4553 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4554 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4555 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4556 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4557 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4558 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4559 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4560 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4561 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4562 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4563 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4564 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4565 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4566 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4567 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4568 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4569 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4570 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4571 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4572 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4573 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4574 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4575 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4576 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4577 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4578 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4579 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4580 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4581 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4582 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4583 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4584 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004585};
4586
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004587/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004588static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004589 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004590 7, /* CONF_HW_RXTX_RATE_MCS7 */
4591 6, /* CONF_HW_RXTX_RATE_MCS6 */
4592 5, /* CONF_HW_RXTX_RATE_MCS5 */
4593 4, /* CONF_HW_RXTX_RATE_MCS4 */
4594 3, /* CONF_HW_RXTX_RATE_MCS3 */
4595 2, /* CONF_HW_RXTX_RATE_MCS2 */
4596 1, /* CONF_HW_RXTX_RATE_MCS1 */
4597 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004598
4599 7, /* CONF_HW_RXTX_RATE_54 */
4600 6, /* CONF_HW_RXTX_RATE_48 */
4601 5, /* CONF_HW_RXTX_RATE_36 */
4602 4, /* CONF_HW_RXTX_RATE_24 */
4603
4604 /* TI-specific rate */
4605 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4606
4607 3, /* CONF_HW_RXTX_RATE_18 */
4608 2, /* CONF_HW_RXTX_RATE_12 */
4609 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4610 1, /* CONF_HW_RXTX_RATE_9 */
4611 0, /* CONF_HW_RXTX_RATE_6 */
4612 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4613 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4614 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4615};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004616
4617static struct ieee80211_supported_band wl1271_band_5ghz = {
4618 .channels = wl1271_channels_5ghz,
4619 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4620 .bitrates = wl1271_rates_5ghz,
4621 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004622 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004623};
4624
Tobias Klausera0ea9492010-05-20 10:38:11 +02004625static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004626 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4627 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4628};
4629
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004630static const struct ieee80211_ops wl1271_ops = {
4631 .start = wl1271_op_start,
4632 .stop = wl1271_op_stop,
4633 .add_interface = wl1271_op_add_interface,
4634 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004635 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004636#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004637 .suspend = wl1271_op_suspend,
4638 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004639#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004640 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004641 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004642 .configure_filter = wl1271_op_configure_filter,
4643 .tx = wl1271_op_tx,
4644 .set_key = wl1271_op_set_key,
4645 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004646 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004647 .sched_scan_start = wl1271_op_sched_scan_start,
4648 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004649 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004650 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004651 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004652 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004653 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004654 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004655 .sta_add = wl1271_op_sta_add,
4656 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004657 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004658 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004659 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004660 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004661 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004662};
4663
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004664
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004665u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004666{
4667 u8 idx;
4668
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004669 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004670
4671 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4672 wl1271_error("Illegal RX rate from HW: %d", rate);
4673 return 0;
4674 }
4675
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004676 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004677 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4678 wl1271_error("Unsupported RX rate from HW: %d", rate);
4679 return 0;
4680 }
4681
4682 return idx;
4683}
4684
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004685static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4686 struct device_attribute *attr,
4687 char *buf)
4688{
4689 struct wl1271 *wl = dev_get_drvdata(dev);
4690 ssize_t len;
4691
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004692 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004693
4694 mutex_lock(&wl->mutex);
4695 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4696 wl->sg_enabled);
4697 mutex_unlock(&wl->mutex);
4698
4699 return len;
4700
4701}
4702
4703static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4704 struct device_attribute *attr,
4705 const char *buf, size_t count)
4706{
4707 struct wl1271 *wl = dev_get_drvdata(dev);
4708 unsigned long res;
4709 int ret;
4710
Luciano Coelho6277ed62011-04-01 17:49:54 +03004711 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004712 if (ret < 0) {
4713 wl1271_warning("incorrect value written to bt_coex_mode");
4714 return count;
4715 }
4716
4717 mutex_lock(&wl->mutex);
4718
4719 res = !!res;
4720
4721 if (res == wl->sg_enabled)
4722 goto out;
4723
4724 wl->sg_enabled = res;
4725
4726 if (wl->state == WL1271_STATE_OFF)
4727 goto out;
4728
Ido Yariva6208652011-03-01 15:14:41 +02004729 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004730 if (ret < 0)
4731 goto out;
4732
4733 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4734 wl1271_ps_elp_sleep(wl);
4735
4736 out:
4737 mutex_unlock(&wl->mutex);
4738 return count;
4739}
4740
4741static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4742 wl1271_sysfs_show_bt_coex_state,
4743 wl1271_sysfs_store_bt_coex_state);
4744
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004745static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4746 struct device_attribute *attr,
4747 char *buf)
4748{
4749 struct wl1271 *wl = dev_get_drvdata(dev);
4750 ssize_t len;
4751
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004752 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004753
4754 mutex_lock(&wl->mutex);
4755 if (wl->hw_pg_ver >= 0)
4756 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4757 else
4758 len = snprintf(buf, len, "n/a\n");
4759 mutex_unlock(&wl->mutex);
4760
4761 return len;
4762}
4763
Gery Kahn6f07b722011-07-18 14:21:49 +03004764static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004765 wl1271_sysfs_show_hw_pg_ver, NULL);
4766
Ido Yariv95dac04f2011-06-06 14:57:06 +03004767static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4768 struct bin_attribute *bin_attr,
4769 char *buffer, loff_t pos, size_t count)
4770{
4771 struct device *dev = container_of(kobj, struct device, kobj);
4772 struct wl1271 *wl = dev_get_drvdata(dev);
4773 ssize_t len;
4774 int ret;
4775
4776 ret = mutex_lock_interruptible(&wl->mutex);
4777 if (ret < 0)
4778 return -ERESTARTSYS;
4779
4780 /* Let only one thread read the log at a time, blocking others */
4781 while (wl->fwlog_size == 0) {
4782 DEFINE_WAIT(wait);
4783
4784 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4785 &wait,
4786 TASK_INTERRUPTIBLE);
4787
4788 if (wl->fwlog_size != 0) {
4789 finish_wait(&wl->fwlog_waitq, &wait);
4790 break;
4791 }
4792
4793 mutex_unlock(&wl->mutex);
4794
4795 schedule();
4796 finish_wait(&wl->fwlog_waitq, &wait);
4797
4798 if (signal_pending(current))
4799 return -ERESTARTSYS;
4800
4801 ret = mutex_lock_interruptible(&wl->mutex);
4802 if (ret < 0)
4803 return -ERESTARTSYS;
4804 }
4805
4806 /* Check if the fwlog is still valid */
4807 if (wl->fwlog_size < 0) {
4808 mutex_unlock(&wl->mutex);
4809 return 0;
4810 }
4811
4812 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4813 len = min(count, (size_t)wl->fwlog_size);
4814 wl->fwlog_size -= len;
4815 memcpy(buffer, wl->fwlog, len);
4816
4817 /* Make room for new messages */
4818 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4819
4820 mutex_unlock(&wl->mutex);
4821
4822 return len;
4823}
4824
4825static struct bin_attribute fwlog_attr = {
4826 .attr = {.name = "fwlog", .mode = S_IRUSR},
4827 .read = wl1271_sysfs_read_fwlog,
4828};
4829
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004830static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004831{
4832 int ret;
4833
4834 if (wl->mac80211_registered)
4835 return 0;
4836
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004837 ret = wl1271_fetch_nvs(wl);
4838 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004839 /* NOTE: The wl->nvs->nvs element must be first, in
4840 * order to simplify the casting, we assume it is at
4841 * the beginning of the wl->nvs structure.
4842 */
4843 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004844
4845 wl->mac_addr[0] = nvs_ptr[11];
4846 wl->mac_addr[1] = nvs_ptr[10];
4847 wl->mac_addr[2] = nvs_ptr[6];
4848 wl->mac_addr[3] = nvs_ptr[5];
4849 wl->mac_addr[4] = nvs_ptr[4];
4850 wl->mac_addr[5] = nvs_ptr[3];
4851 }
4852
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004853 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4854
4855 ret = ieee80211_register_hw(wl->hw);
4856 if (ret < 0) {
4857 wl1271_error("unable to register mac80211 hw: %d", ret);
4858 return ret;
4859 }
4860
4861 wl->mac80211_registered = true;
4862
Eliad Pellerd60080a2010-11-24 12:53:16 +02004863 wl1271_debugfs_init(wl);
4864
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004865 register_netdevice_notifier(&wl1271_dev_notifier);
4866
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004867 wl1271_notice("loaded");
4868
4869 return 0;
4870}
4871
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004872static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004873{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004874 if (wl->state == WL1271_STATE_PLT)
4875 __wl1271_plt_stop(wl);
4876
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004877 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004878 ieee80211_unregister_hw(wl->hw);
4879 wl->mac80211_registered = false;
4880
4881}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004882
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004883static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004884{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004885 static const u32 cipher_suites[] = {
4886 WLAN_CIPHER_SUITE_WEP40,
4887 WLAN_CIPHER_SUITE_WEP104,
4888 WLAN_CIPHER_SUITE_TKIP,
4889 WLAN_CIPHER_SUITE_CCMP,
4890 WL1271_CIPHER_SUITE_GEM,
4891 };
4892
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004893 /* The tx descriptor buffer and the TKIP space. */
4894 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4895 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004896
4897 /* unit us */
4898 /* FIXME: find a proper value */
4899 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004900 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004901
4902 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004903 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004904 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004905 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004906 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004907 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004908 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004909 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004910 IEEE80211_HW_AP_LINK_PS |
4911 IEEE80211_HW_AMPDU_AGGREGATION |
4912 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004913
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004914 wl->hw->wiphy->cipher_suites = cipher_suites;
4915 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4916
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004917 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004918 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4919 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004920 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004921 wl->hw->wiphy->max_sched_scan_ssids = 16;
4922 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004923 /*
4924 * Maximum length of elements in scanning probe request templates
4925 * should be the maximum length possible for a template, without
4926 * the IEEE80211 header of the template
4927 */
Eliad Peller154037d2011-08-14 13:17:12 +03004928 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004929 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004930
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004931 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4932 sizeof(struct ieee80211_header);
4933
Eliad Peller1ec23f72011-08-25 14:26:54 +03004934 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4935
Luciano Coelho4a31c112011-03-21 23:16:14 +02004936 /* make sure all our channels fit in the scanned_ch bitmask */
4937 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4938 ARRAY_SIZE(wl1271_channels_5ghz) >
4939 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004940 /*
4941 * We keep local copies of the band structs because we need to
4942 * modify them on a per-device basis.
4943 */
4944 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4945 sizeof(wl1271_band_2ghz));
4946 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4947 sizeof(wl1271_band_5ghz));
4948
4949 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4950 &wl->bands[IEEE80211_BAND_2GHZ];
4951 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4952 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004953
Kalle Valo12bd8942010-03-18 12:26:33 +02004954 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004955 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004956
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004957 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4958
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02004959 /* the FW answers probe-requests in AP-mode */
4960 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
4961 wl->hw->wiphy->probe_resp_offload =
4962 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
4963 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
4964 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
4965
Felipe Balbia390e852011-10-06 10:07:44 +03004966 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004967
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004968 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004969 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004970
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004971 wl->hw->max_rx_aggregation_subframes = 8;
4972
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004973 return 0;
4974}
4975
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004976#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004977
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004978static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004979{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004980 struct ieee80211_hw *hw;
4981 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004982 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004983 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004984
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004985 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004986
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004987 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4988 if (!hw) {
4989 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004990 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004991 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004992 }
4993
4994 wl = hw->priv;
4995 memset(wl, 0, sizeof(*wl));
4996
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004997 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02004998 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004999
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005000 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005001
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005002 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005003 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005004 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5005
Ido Yariva6208652011-03-01 15:14:41 +02005006 skb_queue_head_init(&wl->deferred_rx_queue);
5007 skb_queue_head_init(&wl->deferred_tx_queue);
5008
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005009 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005010 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005011 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5012 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5013 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005014
Eliad Peller92ef8962011-06-07 12:50:46 +03005015 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5016 if (!wl->freezable_wq) {
5017 ret = -ENOMEM;
5018 goto err_hw;
5019 }
5020
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005021 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005022 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005023 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005024 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005025 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005026 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005027 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005028 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005029 wl->ap_ps_map = 0;
5030 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005031 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005032 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005033 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005034 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005035 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005036 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005037 wl->fwlog_size = 0;
5038 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005039
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005040 /* The system link is always allocated */
5041 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5042
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005043 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005044 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005045 wl->tx_frames[i] = NULL;
5046
5047 spin_lock_init(&wl->wl_lock);
5048
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005049 wl->state = WL1271_STATE_OFF;
5050 mutex_init(&wl->mutex);
5051
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005052 /* Apply default driver configuration. */
5053 wl1271_conf_init(wl);
5054
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005055 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5056 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5057 if (!wl->aggr_buf) {
5058 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005059 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005060 }
5061
Ido Yariv990f5de2011-03-31 10:06:59 +02005062 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5063 if (!wl->dummy_packet) {
5064 ret = -ENOMEM;
5065 goto err_aggr;
5066 }
5067
Ido Yariv95dac04f2011-06-06 14:57:06 +03005068 /* Allocate one page for the FW log */
5069 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5070 if (!wl->fwlog) {
5071 ret = -ENOMEM;
5072 goto err_dummy_packet;
5073 }
5074
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005075 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005076
Ido Yariv990f5de2011-03-31 10:06:59 +02005077err_dummy_packet:
5078 dev_kfree_skb(wl->dummy_packet);
5079
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005080err_aggr:
5081 free_pages((unsigned long)wl->aggr_buf, order);
5082
Eliad Peller92ef8962011-06-07 12:50:46 +03005083err_wq:
5084 destroy_workqueue(wl->freezable_wq);
5085
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005086err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005087 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005088 ieee80211_free_hw(hw);
5089
5090err_hw_alloc:
5091
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005092 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005093}
5094
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005095static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005096{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005097 /* Unblock any fwlog readers */
5098 mutex_lock(&wl->mutex);
5099 wl->fwlog_size = -1;
5100 wake_up_interruptible_all(&wl->fwlog_waitq);
5101 mutex_unlock(&wl->mutex);
5102
Felipe Balbif79f8902011-10-06 13:05:25 +03005103 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005104
Felipe Balbif79f8902011-10-06 13:05:25 +03005105 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005106
Felipe Balbif79f8902011-10-06 13:05:25 +03005107 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005108 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005109 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005110 free_pages((unsigned long)wl->aggr_buf,
5111 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005112
5113 wl1271_debugfs_exit(wl);
5114
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005115 vfree(wl->fw);
5116 wl->fw = NULL;
5117 kfree(wl->nvs);
5118 wl->nvs = NULL;
5119
5120 kfree(wl->fw_status);
5121 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005122 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005123
5124 ieee80211_free_hw(wl->hw);
5125
5126 return 0;
5127}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005128
Felipe Balbia390e852011-10-06 10:07:44 +03005129static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5130{
5131 struct wl1271 *wl = cookie;
5132 unsigned long flags;
5133
5134 wl1271_debug(DEBUG_IRQ, "IRQ");
5135
5136 /* complete the ELP completion */
5137 spin_lock_irqsave(&wl->wl_lock, flags);
5138 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5139 if (wl->elp_compl) {
5140 complete(wl->elp_compl);
5141 wl->elp_compl = NULL;
5142 }
5143
5144 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5145 /* don't enqueue a work right now. mark it as pending */
5146 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5147 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5148 disable_irq_nosync(wl->irq);
5149 pm_wakeup_event(wl->dev, 0);
5150 spin_unlock_irqrestore(&wl->wl_lock, flags);
5151 return IRQ_HANDLED;
5152 }
5153 spin_unlock_irqrestore(&wl->wl_lock, flags);
5154
5155 return IRQ_WAKE_THREAD;
5156}
5157
Felipe Balbice2a2172011-10-05 14:12:55 +03005158static int __devinit wl12xx_probe(struct platform_device *pdev)
5159{
Felipe Balbia390e852011-10-06 10:07:44 +03005160 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5161 struct ieee80211_hw *hw;
5162 struct wl1271 *wl;
5163 unsigned long irqflags;
5164 int ret = -ENODEV;
5165
5166 hw = wl1271_alloc_hw();
5167 if (IS_ERR(hw)) {
5168 wl1271_error("can't allocate hw");
5169 ret = PTR_ERR(hw);
5170 goto out;
5171 }
5172
5173 wl = hw->priv;
5174 wl->irq = platform_get_irq(pdev, 0);
5175 wl->ref_clock = pdata->board_ref_clock;
5176 wl->tcxo_clock = pdata->board_tcxo_clock;
5177 wl->platform_quirks = pdata->platform_quirks;
5178 wl->set_power = pdata->set_power;
5179 wl->dev = &pdev->dev;
5180 wl->if_ops = pdata->ops;
5181
5182 platform_set_drvdata(pdev, wl);
5183
5184 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5185 irqflags = IRQF_TRIGGER_RISING;
5186 else
5187 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5188
5189 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5190 irqflags,
5191 pdev->name, wl);
5192 if (ret < 0) {
5193 wl1271_error("request_irq() failed: %d", ret);
5194 goto out_free_hw;
5195 }
5196
5197 ret = enable_irq_wake(wl->irq);
5198 if (!ret) {
5199 wl->irq_wake_enabled = true;
5200 device_init_wakeup(wl->dev, 1);
5201 if (pdata->pwr_in_suspend)
5202 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5203
5204 }
5205 disable_irq(wl->irq);
5206
5207 ret = wl1271_init_ieee80211(wl);
5208 if (ret)
5209 goto out_irq;
5210
5211 ret = wl1271_register_hw(wl);
5212 if (ret)
5213 goto out_irq;
5214
Felipe Balbif79f8902011-10-06 13:05:25 +03005215 /* Create sysfs file to control bt coex state */
5216 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5217 if (ret < 0) {
5218 wl1271_error("failed to create sysfs file bt_coex_state");
5219 goto out_irq;
5220 }
5221
5222 /* Create sysfs file to get HW PG version */
5223 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5224 if (ret < 0) {
5225 wl1271_error("failed to create sysfs file hw_pg_ver");
5226 goto out_bt_coex_state;
5227 }
5228
5229 /* Create sysfs file for the FW log */
5230 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5231 if (ret < 0) {
5232 wl1271_error("failed to create sysfs file fwlog");
5233 goto out_hw_pg_ver;
5234 }
5235
Felipe Balbice2a2172011-10-05 14:12:55 +03005236 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005237
Felipe Balbif79f8902011-10-06 13:05:25 +03005238out_hw_pg_ver:
5239 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5240
5241out_bt_coex_state:
5242 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5243
Felipe Balbia390e852011-10-06 10:07:44 +03005244out_irq:
5245 free_irq(wl->irq, wl);
5246
5247out_free_hw:
5248 wl1271_free_hw(wl);
5249
5250out:
5251 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005252}
5253
5254static int __devexit wl12xx_remove(struct platform_device *pdev)
5255{
Felipe Balbia390e852011-10-06 10:07:44 +03005256 struct wl1271 *wl = platform_get_drvdata(pdev);
5257
5258 if (wl->irq_wake_enabled) {
5259 device_init_wakeup(wl->dev, 0);
5260 disable_irq_wake(wl->irq);
5261 }
5262 wl1271_unregister_hw(wl);
5263 free_irq(wl->irq, wl);
5264 wl1271_free_hw(wl);
5265
Felipe Balbice2a2172011-10-05 14:12:55 +03005266 return 0;
5267}
5268
5269static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005270 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005271 { } /* 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 = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005280 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005281 .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>");