blob: 9e9fb3fb8f01e697d891bd4b87e833a1620cae0b [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Felipe Balbia390e852011-10-06 10:07:44 +030035#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "wl12xx.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030038#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030039#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000040#include "reg.h"
41#include "io.h"
42#include "event.h"
43#include "tx.h"
44#include "rx.h"
45#include "ps.h"
46#include "init.h"
47#include "debugfs.h"
48#include "cmd.h"
49#include "boot.h"
50#include "testmode.h"
51#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030052
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020053#define WL1271_BOOT_RETRIES 3
54
Juuso Oikarinen8a080482009-10-13 12:47:44 +030055static struct conf_drv_settings default_conf = {
56 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030057 .params = {
58 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
61 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
62 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
64 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
65 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
66 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
68 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
69 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
70 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
71 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
73 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
74 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
75 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
76 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
77 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
78 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
79 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
82 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
83 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
84 /* active scan params */
85 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
86 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
87 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
88 /* passive scan params */
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
91 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
92 /* passive scan in dual antenna params */
93 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
94 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
95 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
96 /* general params */
97 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
98 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
99 [CONF_SG_BEACON_MISS_PERCENT] = 60,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_RXT] = 1200,
102 [CONF_SG_TXT] = 1000,
103 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
104 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
105 [CONF_SG_HV3_MAX_SERVED] = 6,
106 [CONF_SG_PS_POLL_TIMEOUT] = 10,
107 [CONF_SG_UPSD_TIMEOUT] = 10,
108 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
109 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
110 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
111 /* AP params */
112 [CONF_AP_BEACON_MISS_TX] = 3,
113 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
114 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
115 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
116 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
117 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300118 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200119 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300120 },
121 .rx = {
122 .rx_msdu_life_time = 512000,
123 .packet_detection_threshold = 0,
124 .ps_poll_timeout = 15,
125 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300126 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200127 .rx_cca_threshold = 0,
128 .irq_blk_threshold = 0xFFFF,
129 .irq_pkt_threshold = 0,
130 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300131 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
132 },
133 .tx = {
134 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200135 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300136 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300137 .short_retry_limit = 10,
138 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200139 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300140 },
141 .ac_conf_count = 4,
142 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200143 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300144 .ac = CONF_TX_AC_BE,
145 .cw_min = 15,
146 .cw_max = 63,
147 .aifsn = 3,
148 .tx_op_limit = 0,
149 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200150 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300151 .ac = CONF_TX_AC_BK,
152 .cw_min = 15,
153 .cw_max = 63,
154 .aifsn = 7,
155 .tx_op_limit = 0,
156 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200157 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300158 .ac = CONF_TX_AC_VI,
159 .cw_min = 15,
160 .cw_max = 63,
161 .aifsn = CONF_TX_AIFS_PIFS,
162 .tx_op_limit = 3008,
163 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200164 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300165 .ac = CONF_TX_AC_VO,
166 .cw_min = 15,
167 .cw_max = 63,
168 .aifsn = CONF_TX_AIFS_PIFS,
169 .tx_op_limit = 1504,
170 },
171 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300172 .max_tx_retries = 100,
173 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300175 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200176 [CONF_TX_AC_BE] = {
177 .queue_id = CONF_TX_AC_BE,
178 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300179 .tsid = CONF_TX_AC_BE,
180 .ps_scheme = CONF_PS_SCHEME_LEGACY,
181 .ack_policy = CONF_ACK_POLICY_LEGACY,
182 .apsd_conf = {0, 0},
183 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200184 [CONF_TX_AC_BK] = {
185 .queue_id = CONF_TX_AC_BK,
186 .channel_type = CONF_CHANNEL_TYPE_EDCF,
187 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300188 .ps_scheme = CONF_PS_SCHEME_LEGACY,
189 .ack_policy = CONF_ACK_POLICY_LEGACY,
190 .apsd_conf = {0, 0},
191 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200192 [CONF_TX_AC_VI] = {
193 .queue_id = CONF_TX_AC_VI,
194 .channel_type = CONF_CHANNEL_TYPE_EDCF,
195 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .ps_scheme = CONF_PS_SCHEME_LEGACY,
197 .ack_policy = CONF_ACK_POLICY_LEGACY,
198 .apsd_conf = {0, 0},
199 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200200 [CONF_TX_AC_VO] = {
201 .queue_id = CONF_TX_AC_VO,
202 .channel_type = CONF_CHANNEL_TYPE_EDCF,
203 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300204 .ps_scheme = CONF_PS_SCHEME_LEGACY,
205 .ack_policy = CONF_ACK_POLICY_LEGACY,
206 .apsd_conf = {0, 0},
207 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300208 },
209 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200210 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300211 .tx_compl_threshold = 4,
212 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
213 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200214 .tmpl_short_retry_limit = 10,
215 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300216 },
217 .conn = {
218 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300219 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300221 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300222 .bcn_filt_ie = {
223 [0] = {
224 .ie = WLAN_EID_CHANNEL_SWITCH,
225 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300226 },
227 [1] = {
228 .ie = WLAN_EID_HT_INFORMATION,
229 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
230 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200232 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 .bss_lose_timeout = 100,
234 .beacon_rx_timeout = 10000,
235 .broadcast_timeout = 20000,
236 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300237 .ps_poll_threshold = 10,
238 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300239 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200240 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300241 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300242 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200243 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300244 .keep_alive_interval = 55000,
245 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300246 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200247 .itrim = {
248 .enable = false,
249 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200250 },
251 .pm_config = {
252 .host_clk_settling_time = 5000,
253 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 },
255 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300256 .trigger_pacing = 1,
257 .avg_weight_rssi_beacon = 20,
258 .avg_weight_rssi_data = 10,
259 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100260 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200261 },
262 .scan = {
263 .min_dwell_time_active = 7500,
264 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100265 .min_dwell_time_passive = 100000,
266 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200267 .num_probe_reqs = 2,
268 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300269 .sched_scan = {
270 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300271 .min_dwell_time_active = 30,
272 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300274 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300275 .num_probe_reqs = 2,
276 .rssi_threshold = -90,
277 .snr_threshold = 0,
278 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200279 .rf = {
280 .tx_per_channel_power_compensation_2 = {
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 },
283 .tx_per_channel_power_compensation_5 = {
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 },
288 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300290 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100291 .tx_ba_win_size = 64,
292 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300293 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100294 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200295 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200296 .num_stations = 1,
297 .ssid_profiles = 1,
298 .rx_block_num = 70,
299 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300300 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200301 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200302 .min_req_rx_blocks = 22,
303 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200304 },
305 .mem_wl128x = {
306 .num_stations = 1,
307 .ssid_profiles = 1,
308 .rx_block_num = 40,
309 .tx_min_block_num = 40,
310 .dynamic_memory = 1,
311 .min_req_tx_blocks = 45,
312 .min_req_rx_blocks = 22,
313 .tx_min = 27,
314 },
Shahar Leviff868432011-04-11 15:41:46 +0300315 .fm_coex = {
316 .enable = true,
317 .swallow_period = 5,
318 .n_divider_fref_set_1 = 0xff, /* default */
319 .n_divider_fref_set_2 = 12,
320 .m_divider_fref_set_1 = 148,
321 .m_divider_fref_set_2 = 0xffff, /* default */
322 .coex_pll_stabilization_time = 0xffffffff, /* default */
323 .ldo_stabilization_time = 0xffff, /* default */
324 .fm_disturbed_band_margin = 0xff, /* default */
325 .swallow_clk_diff = 0xff, /* default */
326 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300327 .rx_streaming = {
328 .duration = 150,
329 .queues = 0x1,
330 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300331 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300332 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300333 .fwlog = {
334 .mode = WL12XX_FWLOG_ON_DEMAND,
335 .mem_blocks = 2,
336 .severity = 0,
337 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
338 .output = WL12XX_FWLOG_OUTPUT_HOST,
339 .threshold = 0,
340 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300341 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300342 .rate = {
343 .rate_retry_score = 32000,
344 .per_add = 8192,
345 .per_th1 = 2048,
346 .per_th2 = 4096,
347 .max_per = 8100,
348 .inverse_curiosity_factor = 5,
349 .tx_fail_low_th = 4,
350 .tx_fail_high_th = 10,
351 .per_alpha_shift = 4,
352 .per_add_shift = 13,
353 .per_beta1_shift = 10,
354 .per_beta2_shift = 8,
355 .rate_check_up = 2,
356 .rate_check_down = 12,
357 .rate_retry_policy = {
358 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00,
361 },
362 },
Eliad Peller94877752011-08-28 15:11:56 +0300363 .hangover = {
364 .recover_time = 0,
365 .hangover_period = 20,
366 .dynamic_mode = 1,
367 .early_termination_mode = 1,
368 .max_period = 20,
369 .min_period = 1,
370 .increase_delta = 1,
371 .decrease_delta = 2,
372 .quiet_time = 4,
373 .increase_time = 1,
374 .window_size = 16,
375 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300376};
377
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300379static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300380
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300381static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200382 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300383 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200384static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200385static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200386
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200387static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300388static LIST_HEAD(wl_list);
389
Eliad Pellerba8447f2011-10-10 10:13:00 +0200390static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
391 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300392{
393 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200394
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300395 if (operstate != IF_OPER_UP)
396 return 0;
397
Eliad Peller8181aec2011-10-10 10:13:04 +0200398 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300399 return 0;
400
Eliad Peller154da672011-10-05 11:55:53 +0200401 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300402 if (ret < 0)
403 return ret;
404
Eliad Peller0603d892011-10-05 11:55:51 +0200405 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300406
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300407 wl1271_info("Association completed.");
408 return 0;
409}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300410static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
411 void *arg)
412{
413 struct net_device *dev = arg;
414 struct wireless_dev *wdev;
415 struct wiphy *wiphy;
416 struct ieee80211_hw *hw;
417 struct wl1271 *wl;
418 struct wl1271 *wl_temp;
Eliad Pellerba8447f2011-10-10 10:13:00 +0200419 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300420 int ret = 0;
421
422 /* Check that this notification is for us. */
423 if (what != NETDEV_CHANGE)
424 return NOTIFY_DONE;
425
426 wdev = dev->ieee80211_ptr;
427 if (wdev == NULL)
428 return NOTIFY_DONE;
429
430 wiphy = wdev->wiphy;
431 if (wiphy == NULL)
432 return NOTIFY_DONE;
433
434 hw = wiphy_priv(wiphy);
435 if (hw == NULL)
436 return NOTIFY_DONE;
437
438 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200439 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300440 list_for_each_entry(wl, &wl_list, list) {
441 if (wl == wl_temp)
442 break;
443 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200444 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300445 if (wl != wl_temp)
446 return NOTIFY_DONE;
447
448 mutex_lock(&wl->mutex);
449
450 if (wl->state == WL1271_STATE_OFF)
451 goto out;
452
Eliad 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 Oikarinen01ac17e2009-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
Ido Yarivf3df1332012-01-11 09:42:39 +02001394int 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
Ido Yarivf3df1332012-01-11 09:42:39 +02001400 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001401 if (wl->state != WL1271_STATE_PLT) {
Ido Yarivf3df1332012-01-11 09:42:39 +02001402 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001403 wl1271_error("cannot power down because not in PLT "
1404 "state: %d", wl->state);
1405 ret = -EBUSY;
1406 goto out;
1407 }
1408
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001409 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 Yarivf3df1332012-01-11 09:42:39 +02001413
Ido Yariva6208652011-03-01 15:14:41 +02001414 wl1271_disable_interrupts(wl);
1415 wl1271_flush_deferred_work(wl);
1416 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001417 cancel_work_sync(&wl->recovery_work);
Ido Yariva4549692012-01-11 09:42:40 +02001418
1419 mutex_lock(&wl->mutex);
1420 wl1271_power_off(wl);
1421 mutex_unlock(&wl->mutex);
1422
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001423out:
1424 return ret;
1425}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001426
Johannes Berg7bb45682011-02-24 14:42:06 +01001427static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001428{
1429 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001430 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1431 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001432 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001433 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001434 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001435 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001436
Eliad Peller0f168012011-10-11 13:52:25 +02001437 if (vif)
1438 wlvif = wl12xx_vif_to_data(vif);
1439
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001440 mapping = skb_get_queue_mapping(skb);
1441 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001442
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001443 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001444
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001445 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001446
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001447 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001448 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001449 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001450 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001451 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001452 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001453 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001455 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1456 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1457
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001458 wl->tx_queue_count[q]++;
1459
1460 /*
1461 * The workqueue is slow to process the tx_queue and we need stop
1462 * the queue here, otherwise the queue will get too long.
1463 */
1464 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1465 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1466 ieee80211_stop_queue(wl->hw, mapping);
1467 set_bit(q, &wl->stopped_queues_map);
1468 }
1469
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001470 /*
1471 * The chip specific setup must run before the first TX packet -
1472 * before that, the tx_work will not be initialized!
1473 */
1474
Ido Yarivb07d4032011-03-01 15:14:43 +02001475 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1476 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001477 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001478
Arik Nemtsov04216da2011-08-14 13:17:38 +03001479out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001480 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001481}
1482
Shahar Leviae47c452011-03-06 16:32:14 +02001483int wl1271_tx_dummy_packet(struct wl1271 *wl)
1484{
Ido Yariv990f5de2011-03-31 10:06:59 +02001485 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001486 int q;
1487
1488 /* no need to queue a new dummy packet if one is already pending */
1489 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1490 return 0;
1491
1492 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001493
Ido Yariv990f5de2011-03-31 10:06:59 +02001494 spin_lock_irqsave(&wl->wl_lock, flags);
1495 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001496 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001497 spin_unlock_irqrestore(&wl->wl_lock, flags);
1498
1499 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1500 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001501 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001502
1503 /*
1504 * If the FW TX is busy, TX work will be scheduled by the threaded
1505 * interrupt handler function
1506 */
1507 return 0;
1508}
1509
1510/*
1511 * The size of the dummy packet should be at least 1400 bytes. However, in
1512 * order to minimize the number of bus transactions, aligning it to 512 bytes
1513 * boundaries could be beneficial, performance wise
1514 */
1515#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1516
Luciano Coelhocf27d862011-04-01 21:08:23 +03001517static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001518{
1519 struct sk_buff *skb;
1520 struct ieee80211_hdr_3addr *hdr;
1521 unsigned int dummy_packet_size;
1522
1523 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1524 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1525
1526 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001527 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001528 wl1271_warning("Failed to allocate a dummy packet skb");
1529 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001530 }
1531
1532 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1533
1534 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1535 memset(hdr, 0, sizeof(*hdr));
1536 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001537 IEEE80211_STYPE_NULLFUNC |
1538 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001539
Ido Yariv990f5de2011-03-31 10:06:59 +02001540 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001541
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001542 /* Dummy packets require the TID to be management */
1543 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001544
1545 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001546 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001547 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001548
Ido Yariv990f5de2011-03-31 10:06:59 +02001549 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001550}
1551
Ido Yariv990f5de2011-03-31 10:06:59 +02001552
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001553static struct notifier_block wl1271_dev_notifier = {
1554 .notifier_call = wl1271_dev_notify,
1555};
1556
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001557#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001558static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1559 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001560{
Eliad Pellere85d1622011-06-27 13:06:43 +03001561 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001562
Eliad Peller94390642011-05-13 11:57:13 +03001563 mutex_lock(&wl->mutex);
1564
Eliad Pellerba8447f2011-10-10 10:13:00 +02001565 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001566 goto out_unlock;
1567
Eliad Peller94390642011-05-13 11:57:13 +03001568 ret = wl1271_ps_elp_wakeup(wl);
1569 if (ret < 0)
1570 goto out_unlock;
1571
1572 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001573 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001574 DECLARE_COMPLETION_ONSTACK(compl);
1575
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001576 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001577 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001578 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001579 if (ret < 0)
1580 goto out_sleep;
1581
1582 /* we must unlock here so we will be able to get events */
1583 wl1271_ps_elp_sleep(wl);
1584 mutex_unlock(&wl->mutex);
1585
1586 ret = wait_for_completion_timeout(
1587 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
Pontus Fuchsef187062011-12-14 14:32:23 +01001588
1589 mutex_lock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001590 if (ret <= 0) {
1591 wl1271_warning("couldn't enter ps mode!");
1592 ret = -EBUSY;
Pontus Fuchsef187062011-12-14 14:32:23 +01001593 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001594 }
1595
Eliad Peller94390642011-05-13 11:57:13 +03001596 ret = wl1271_ps_elp_wakeup(wl);
1597 if (ret < 0)
Pontus Fuchsef187062011-12-14 14:32:23 +01001598 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001599 }
1600out_sleep:
1601 wl1271_ps_elp_sleep(wl);
Pontus Fuchsef187062011-12-14 14:32:23 +01001602out_cleanup:
1603 wlvif->ps_compl = NULL;
Eliad Peller94390642011-05-13 11:57:13 +03001604out_unlock:
1605 mutex_unlock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001606 return ret;
1607
1608}
1609
Eliad Peller0603d892011-10-05 11:55:51 +02001610static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1611 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001612{
Eliad Pellere85d1622011-06-27 13:06:43 +03001613 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001614
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001615 mutex_lock(&wl->mutex);
1616
Eliad Peller53d40d02011-10-10 10:13:02 +02001617 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001618 goto out_unlock;
1619
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001620 ret = wl1271_ps_elp_wakeup(wl);
1621 if (ret < 0)
1622 goto out_unlock;
1623
Eliad Peller0603d892011-10-05 11:55:51 +02001624 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001625
1626 wl1271_ps_elp_sleep(wl);
1627out_unlock:
1628 mutex_unlock(&wl->mutex);
1629 return ret;
1630
1631}
1632
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001633static int wl1271_configure_suspend(struct wl1271 *wl,
1634 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001635{
Eliad Peller536129c2011-10-05 11:55:45 +02001636 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001637 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001638 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001639 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001640 return 0;
1641}
1642
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001643static void wl1271_configure_resume(struct wl1271 *wl,
1644 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001645{
1646 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001647 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1648 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001649
1650 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001651 return;
1652
1653 mutex_lock(&wl->mutex);
1654 ret = wl1271_ps_elp_wakeup(wl);
1655 if (ret < 0)
1656 goto out;
1657
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001658 if (is_sta) {
1659 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001660 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001661 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001662 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001663 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001664 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001665 }
Eliad Peller94390642011-05-13 11:57:13 +03001666
1667 wl1271_ps_elp_sleep(wl);
1668out:
1669 mutex_unlock(&wl->mutex);
1670}
1671
Eliad Peller402e48612011-05-13 11:57:09 +03001672static int wl1271_op_suspend(struct ieee80211_hw *hw,
1673 struct cfg80211_wowlan *wow)
1674{
1675 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001676 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001677 int ret;
1678
Eliad Peller402e48612011-05-13 11:57:09 +03001679 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001680 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001681
Eliad Peller4a859df2011-06-06 12:21:52 +03001682 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001683 wl12xx_for_each_wlvif(wl, wlvif) {
1684 ret = wl1271_configure_suspend(wl, wlvif);
1685 if (ret < 0) {
1686 wl1271_warning("couldn't prepare device to suspend");
1687 return ret;
1688 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001689 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001690 /* flush any remaining work */
1691 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001692
1693 /*
1694 * disable and re-enable interrupts in order to flush
1695 * the threaded_irq
1696 */
1697 wl1271_disable_interrupts(wl);
1698
1699 /*
1700 * set suspended flag to avoid triggering a new threaded_irq
1701 * work. no need for spinlock as interrupts are disabled.
1702 */
1703 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1704
1705 wl1271_enable_interrupts(wl);
1706 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001707 wl12xx_for_each_wlvif(wl, wlvif) {
1708 flush_delayed_work(&wlvif->pspoll_work);
1709 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001710 flush_delayed_work(&wl->elp_work);
1711
Eliad Peller402e48612011-05-13 11:57:09 +03001712 return 0;
1713}
1714
1715static int wl1271_op_resume(struct ieee80211_hw *hw)
1716{
1717 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001718 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001719 unsigned long flags;
1720 bool run_irq_work = false;
1721
Eliad Peller402e48612011-05-13 11:57:09 +03001722 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1723 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001724 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001725
1726 /*
1727 * re-enable irq_work enqueuing, and call irq_work directly if
1728 * there is a pending work.
1729 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001730 spin_lock_irqsave(&wl->wl_lock, flags);
1731 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1732 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1733 run_irq_work = true;
1734 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001735
Eliad Peller4a859df2011-06-06 12:21:52 +03001736 if (run_irq_work) {
1737 wl1271_debug(DEBUG_MAC80211,
1738 "run postponed irq_work directly");
1739 wl1271_irq(0, wl);
1740 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001741 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001742 wl12xx_for_each_wlvif(wl, wlvif) {
1743 wl1271_configure_resume(wl, wlvif);
1744 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001745 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001746
Eliad Peller402e48612011-05-13 11:57:09 +03001747 return 0;
1748}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001749#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001750
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001751static int wl1271_op_start(struct ieee80211_hw *hw)
1752{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001753 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1754
1755 /*
1756 * We have to delay the booting of the hardware because
1757 * we need to know the local MAC address before downloading and
1758 * initializing the firmware. The MAC address cannot be changed
1759 * after boot, and without the proper MAC address, the firmware
1760 * will not function properly.
1761 *
1762 * The MAC address is first known when the corresponding interface
1763 * is added. That is where we will initialize the hardware.
1764 */
1765
1766 return 0;
1767}
1768
1769static void wl1271_op_stop(struct ieee80211_hw *hw)
1770{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001771 struct wl1271 *wl = hw->priv;
1772 int i;
1773
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001774 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001775
Eliad Peller10c8cd02011-10-10 10:13:06 +02001776 mutex_lock(&wl->mutex);
1777 if (wl->state == WL1271_STATE_OFF) {
1778 mutex_unlock(&wl->mutex);
1779 return;
1780 }
Eliad Pellerbaf62772011-10-10 10:12:52 +02001781 /*
1782 * this must be before the cancel_work calls below, so that the work
1783 * functions don't perform further work.
1784 */
1785 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001786 mutex_unlock(&wl->mutex);
1787
1788 mutex_lock(&wl_list_mutex);
1789 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001790 mutex_unlock(&wl_list_mutex);
1791
1792 wl1271_disable_interrupts(wl);
1793 wl1271_flush_deferred_work(wl);
1794 cancel_delayed_work_sync(&wl->scan_complete_work);
1795 cancel_work_sync(&wl->netstack_work);
1796 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001797 cancel_delayed_work_sync(&wl->elp_work);
1798
1799 /* let's notify MAC80211 about the remaining pending TX frames */
1800 wl12xx_tx_reset(wl, true);
1801 mutex_lock(&wl->mutex);
1802
1803 wl1271_power_off(wl);
1804
1805 wl->band = IEEE80211_BAND_2GHZ;
1806
1807 wl->rx_counter = 0;
1808 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1809 wl->tx_blocks_available = 0;
1810 wl->tx_allocated_blocks = 0;
1811 wl->tx_results_count = 0;
1812 wl->tx_packets_count = 0;
1813 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001814 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1815 wl->ap_fw_ps_map = 0;
1816 wl->ap_ps_map = 0;
1817 wl->sched_scanning = false;
1818 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1819 memset(wl->links_map, 0, sizeof(wl->links_map));
1820 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1821 wl->active_sta_count = 0;
1822
1823 /* The system link is always allocated */
1824 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1825
1826 /*
1827 * this is performed after the cancel_work calls and the associated
1828 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1829 * get executed before all these vars have been reset.
1830 */
1831 wl->flags = 0;
1832
1833 wl->tx_blocks_freed = 0;
1834
1835 for (i = 0; i < NUM_TX_QUEUES; i++) {
1836 wl->tx_pkts_freed[i] = 0;
1837 wl->tx_allocated_pkts[i] = 0;
1838 }
1839
1840 wl1271_debugfs_reset(wl);
1841
1842 kfree(wl->fw_status);
1843 wl->fw_status = NULL;
1844 kfree(wl->tx_res_if);
1845 wl->tx_res_if = NULL;
1846 kfree(wl->target_mem_map);
1847 wl->target_mem_map = NULL;
1848
1849 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001850}
1851
Eliad Pellere5a359f2011-10-10 10:13:15 +02001852static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1853{
1854 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1855 WL12XX_MAX_RATE_POLICIES);
1856 if (policy >= WL12XX_MAX_RATE_POLICIES)
1857 return -EBUSY;
1858
1859 __set_bit(policy, wl->rate_policies_map);
1860 *idx = policy;
1861 return 0;
1862}
1863
1864static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1865{
1866 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1867 return;
1868
1869 __clear_bit(*idx, wl->rate_policies_map);
1870 *idx = WL12XX_MAX_RATE_POLICIES;
1871}
1872
Eliad Peller536129c2011-10-05 11:55:45 +02001873static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001874{
Eliad Peller536129c2011-10-05 11:55:45 +02001875 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001876 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001877 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001878 return WL1271_ROLE_P2P_GO;
1879 else
1880 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001881
1882 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001883 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001884 return WL1271_ROLE_P2P_CL;
1885 else
1886 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001887
Eliad Peller227e81e2011-08-14 13:17:26 +03001888 case BSS_TYPE_IBSS:
1889 return WL1271_ROLE_IBSS;
1890
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001891 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001892 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001893 }
1894 return WL12XX_INVALID_ROLE_TYPE;
1895}
1896
Eliad Peller83587502011-10-10 10:12:53 +02001897static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001898{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001899 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001900 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001901
Eliad Peller48e93e42011-10-10 10:12:58 +02001902 /* clear everything but the persistent data */
1903 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001904
1905 switch (ieee80211_vif_type_p2p(vif)) {
1906 case NL80211_IFTYPE_P2P_CLIENT:
1907 wlvif->p2p = 1;
1908 /* fall-through */
1909 case NL80211_IFTYPE_STATION:
1910 wlvif->bss_type = BSS_TYPE_STA_BSS;
1911 break;
1912 case NL80211_IFTYPE_ADHOC:
1913 wlvif->bss_type = BSS_TYPE_IBSS;
1914 break;
1915 case NL80211_IFTYPE_P2P_GO:
1916 wlvif->p2p = 1;
1917 /* fall-through */
1918 case NL80211_IFTYPE_AP:
1919 wlvif->bss_type = BSS_TYPE_AP_BSS;
1920 break;
1921 default:
1922 wlvif->bss_type = MAX_BSS_TYPE;
1923 return -EOPNOTSUPP;
1924 }
1925
Eliad Peller0603d892011-10-05 11:55:51 +02001926 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001927 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001928 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001929
Eliad Pellere936bbe2011-10-05 11:55:56 +02001930 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1931 wlvif->bss_type == BSS_TYPE_IBSS) {
1932 /* init sta/ibss data */
1933 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001934 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1935 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1936 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001937 } else {
1938 /* init ap data */
1939 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1940 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001941 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1942 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1943 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1944 wl12xx_allocate_rate_policy(wl,
1945 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001946 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001947
Eliad Peller83587502011-10-10 10:12:53 +02001948 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1949 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001950 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001951 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001952 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001953 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1954
Eliad Peller1b92f152011-10-10 10:13:09 +02001955 /*
1956 * mac80211 configures some values globally, while we treat them
1957 * per-interface. thus, on init, we have to copy them from wl
1958 */
1959 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001960 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001961 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02001962
Eliad Peller9eb599e2011-10-10 10:12:59 +02001963 INIT_WORK(&wlvif->rx_streaming_enable_work,
1964 wl1271_rx_streaming_enable_work);
1965 INIT_WORK(&wlvif->rx_streaming_disable_work,
1966 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02001967 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02001968 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001969
Eliad Peller9eb599e2011-10-10 10:12:59 +02001970 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1971 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001972 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001973}
1974
Eliad Peller1d095472011-10-10 10:12:49 +02001975static bool wl12xx_init_fw(struct wl1271 *wl)
1976{
1977 int retries = WL1271_BOOT_RETRIES;
1978 bool booted = false;
1979 struct wiphy *wiphy = wl->hw->wiphy;
1980 int ret;
1981
1982 while (retries) {
1983 retries--;
1984 ret = wl1271_chip_wakeup(wl);
1985 if (ret < 0)
1986 goto power_off;
1987
1988 ret = wl1271_boot(wl);
1989 if (ret < 0)
1990 goto power_off;
1991
1992 ret = wl1271_hw_init(wl);
1993 if (ret < 0)
1994 goto irq_disable;
1995
1996 booted = true;
1997 break;
1998
1999irq_disable:
2000 mutex_unlock(&wl->mutex);
2001 /* Unlocking the mutex in the middle of handling is
2002 inherently unsafe. In this case we deem it safe to do,
2003 because we need to let any possibly pending IRQ out of
2004 the system (and while we are WL1271_STATE_OFF the IRQ
2005 work function will not do anything.) Also, any other
2006 possible concurrent operations will fail due to the
2007 current state, hence the wl1271 struct should be safe. */
2008 wl1271_disable_interrupts(wl);
2009 wl1271_flush_deferred_work(wl);
2010 cancel_work_sync(&wl->netstack_work);
2011 mutex_lock(&wl->mutex);
2012power_off:
2013 wl1271_power_off(wl);
2014 }
2015
2016 if (!booted) {
2017 wl1271_error("firmware boot failed despite %d retries",
2018 WL1271_BOOT_RETRIES);
2019 goto out;
2020 }
2021
2022 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2023
2024 /* update hw/fw version info in wiphy struct */
2025 wiphy->hw_version = wl->chip.id;
2026 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2027 sizeof(wiphy->fw_version));
2028
2029 /*
2030 * Now we know if 11a is supported (info from the NVS), so disable
2031 * 11a channels if not supported
2032 */
2033 if (!wl->enable_11a)
2034 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2035
2036 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2037 wl->enable_11a ? "" : "not ");
2038
2039 wl->state = WL1271_STATE_ON;
2040out:
2041 return booted;
2042}
2043
Eliad Peller92e712d2011-12-18 20:25:43 +02002044static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2045{
2046 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2047}
2048
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002049static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2050 struct ieee80211_vif *vif)
2051{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002053 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002054 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002055 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002056 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002057
Johannes Bergea086352012-01-19 09:29:58 +01002058 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2059 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002060
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002061 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002062 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002063
2064 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002065 ret = wl1271_ps_elp_wakeup(wl);
2066 if (ret < 0)
2067 goto out_unlock;
2068
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002069 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002070 wl1271_debug(DEBUG_MAC80211,
2071 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002072 ret = -EBUSY;
2073 goto out;
2074 }
2075
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002076 /*
2077 * in some very corner case HW recovery scenarios its possible to
2078 * get here before __wl1271_op_remove_interface is complete, so
2079 * opt out if that is the case.
2080 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002081 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2082 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002083 ret = -EBUSY;
2084 goto out;
2085 }
2086
Eliad Peller83587502011-10-10 10:12:53 +02002087 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002088 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002089 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002090
Eliad Peller252efa42011-10-05 11:56:00 +02002091 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002092 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002093 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2094 ret = -EINVAL;
2095 goto out;
2096 }
Eliad Peller1d095472011-10-10 10:12:49 +02002097
Eliad Peller784f6942011-10-05 11:55:39 +02002098 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002099 * TODO: after the nvs issue will be solved, move this block
2100 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002101 */
Eliad Peller1d095472011-10-10 10:12:49 +02002102 if (wl->state == WL1271_STATE_OFF) {
2103 /*
2104 * we still need this in order to configure the fw
2105 * while uploading the nvs
2106 */
2107 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002108
Eliad Peller1d095472011-10-10 10:12:49 +02002109 booted = wl12xx_init_fw(wl);
2110 if (!booted) {
2111 ret = -EINVAL;
2112 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002113 }
Eliad Peller1d095472011-10-10 10:12:49 +02002114 }
Eliad Peller04e80792011-08-14 13:17:09 +03002115
Eliad Peller1d095472011-10-10 10:12:49 +02002116 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2117 wlvif->bss_type == BSS_TYPE_IBSS) {
2118 /*
2119 * The device role is a special role used for
2120 * rx and tx frames prior to association (as
2121 * the STA role can get packets only from
2122 * its associated bssid)
2123 */
Eliad Peller784f6942011-10-05 11:55:39 +02002124 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002125 WL1271_ROLE_DEVICE,
2126 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002127 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002128 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002129 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002130
Eliad Peller1d095472011-10-10 10:12:49 +02002131 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2132 role_type, &wlvif->role_id);
2133 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002134 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002135
2136 ret = wl1271_init_vif_specific(wl, vif);
2137 if (ret < 0)
2138 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002139
2140 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002141 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002142 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002143
2144 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2145 wl->ap_count++;
2146 else
2147 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002148out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002149 wl1271_ps_elp_sleep(wl);
2150out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002151 mutex_unlock(&wl->mutex);
2152
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002153 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002154 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002155 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002156 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002157
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002158 return ret;
2159}
2160
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002161static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002162 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002163 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002164{
Eliad Peller536129c2011-10-05 11:55:45 +02002165 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002166 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002167
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002168 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002169
Eliad Peller10c8cd02011-10-10 10:13:06 +02002170 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2171 return;
2172
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002173 wl->vif = NULL;
2174
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002175 /* because of hardware recovery, we may get here twice */
2176 if (wl->state != WL1271_STATE_ON)
2177 return;
2178
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002179 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002180
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002181 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002182 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002183 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002184
Eliad Pellerbaf62772011-10-10 10:12:52 +02002185 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2186 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002187 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002188 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002189 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002190 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002191 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002192 }
2193
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002194 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2195 /* disable active roles */
2196 ret = wl1271_ps_elp_wakeup(wl);
2197 if (ret < 0)
2198 goto deinit;
2199
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002200 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2201 wlvif->bss_type == BSS_TYPE_IBSS) {
2202 if (wl12xx_dev_role_started(wlvif))
2203 wl12xx_stop_dev(wl, wlvif);
2204
Eliad Peller7edebf52011-10-05 11:55:52 +02002205 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002206 if (ret < 0)
2207 goto deinit;
2208 }
2209
Eliad Peller0603d892011-10-05 11:55:51 +02002210 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002211 if (ret < 0)
2212 goto deinit;
2213
2214 wl1271_ps_elp_sleep(wl);
2215 }
2216deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002217 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002218 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002219
2220 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2221 wlvif->bss_type == BSS_TYPE_IBSS) {
2222 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2223 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2224 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2225 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2226 } else {
2227 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2228 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2229 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2230 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2231 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2232 wl12xx_free_rate_policy(wl,
2233 &wlvif->ap.ucast_rate_idx[i]);
2234 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002235
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002236 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002237 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002238 if (wl->last_wlvif == wlvif)
2239 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002240 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002241 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002242 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002243 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002244
Eliad Pellera4e41302011-10-11 11:49:15 +02002245 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2246 wl->ap_count--;
2247 else
2248 wl->sta_count--;
2249
Eliad Pellerbaf62772011-10-10 10:12:52 +02002250 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002251 del_timer_sync(&wlvif->rx_streaming_timer);
2252 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2253 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002254 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002255
Eliad Pellerbaf62772011-10-10 10:12:52 +02002256 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002257}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002258
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002259static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2260 struct ieee80211_vif *vif)
2261{
2262 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002263 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002264 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002265
2266 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002267
2268 if (wl->state == WL1271_STATE_OFF ||
2269 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2270 goto out;
2271
Juuso Oikarinen67353292010-11-18 15:19:02 +02002272 /*
2273 * wl->vif can be null here if someone shuts down the interface
2274 * just when hardware recovery has been started.
2275 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002276 wl12xx_for_each_wlvif(wl, iter) {
2277 if (iter != wlvif)
2278 continue;
2279
Eliad Peller536129c2011-10-05 11:55:45 +02002280 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002281 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002282 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002283 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002284out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002285 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002286 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002287}
2288
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002289static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2290 struct ieee80211_vif *vif,
2291 enum nl80211_iftype new_type, bool p2p)
2292{
2293 wl1271_op_remove_interface(hw, vif);
2294
2295 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2296 vif->p2p = p2p;
2297 return wl1271_op_add_interface(hw, vif);
2298}
2299
Eliad Peller87fbcb02011-10-05 11:55:41 +02002300static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2301 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002302{
2303 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002304 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002305
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002306 /*
2307 * One of the side effects of the JOIN command is that is clears
2308 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2309 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002310 * Currently the only valid scenario for JOIN during association
2311 * is on roaming, in which case we will also be given new keys.
2312 * Keep the below message for now, unless it starts bothering
2313 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002314 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002315 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002316 wl1271_info("JOIN while associated.");
2317
2318 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002319 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002320
Eliad Peller227e81e2011-08-14 13:17:26 +03002321 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002322 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002323 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002324 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002325 if (ret < 0)
2326 goto out;
2327
Eliad Pellerba8447f2011-10-10 10:13:00 +02002328 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002329 goto out;
2330
2331 /*
2332 * The join command disable the keep-alive mode, shut down its process,
2333 * and also clear the template config, so we need to reset it all after
2334 * the join. The acx_aid starts the keep-alive process, and the order
2335 * of the commands below is relevant.
2336 */
Eliad Peller0603d892011-10-05 11:55:51 +02002337 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002338 if (ret < 0)
2339 goto out;
2340
Eliad Peller0603d892011-10-05 11:55:51 +02002341 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002342 if (ret < 0)
2343 goto out;
2344
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002345 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002346 if (ret < 0)
2347 goto out;
2348
Eliad Peller0603d892011-10-05 11:55:51 +02002349 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2350 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002351 ACX_KEEP_ALIVE_TPL_VALID);
2352 if (ret < 0)
2353 goto out;
2354
2355out:
2356 return ret;
2357}
2358
Eliad Peller0603d892011-10-05 11:55:51 +02002359static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002360{
2361 int ret;
2362
Eliad Peller52630c52011-10-10 10:13:08 +02002363 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002364 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2365
Shahar Levi6d158ff2011-09-08 13:01:33 +03002366 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002367 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002368 }
2369
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002370 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002371 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002372 if (ret < 0)
2373 goto out;
2374
Oz Krakowskib992c682011-06-26 10:36:02 +03002375 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002376 wlvif->tx_security_last_seq_lsb = 0;
2377 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002378
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002379out:
2380 return ret;
2381}
2382
Eliad Peller87fbcb02011-10-05 11:55:41 +02002383static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002384{
Eliad Peller1b92f152011-10-10 10:13:09 +02002385 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002386 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002387}
2388
Eliad Peller87fbcb02011-10-05 11:55:41 +02002389static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2390 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002391{
2392 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002393 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2394
2395 if (idle == cur_idle)
2396 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002397
2398 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002399 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002400 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002401 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002402 if (ret < 0)
2403 goto out;
2404 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002405 wlvif->rate_set =
2406 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2407 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002408 if (ret < 0)
2409 goto out;
2410 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002411 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002412 ACX_KEEP_ALIVE_TPL_INVALID);
2413 if (ret < 0)
2414 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002415 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002416 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002417 /* The current firmware only supports sched_scan in idle */
2418 if (wl->sched_scanning) {
2419 wl1271_scan_sched_scan_stop(wl);
2420 ieee80211_sched_scan_stopped(wl->hw);
2421 }
2422
Eliad Peller679a6732011-10-11 11:55:44 +02002423 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002424 if (ret < 0)
2425 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002426 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002427 }
2428
2429out:
2430 return ret;
2431}
2432
Eliad Peller9f259c42011-10-10 10:13:12 +02002433static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2434 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002435{
Eliad Peller9f259c42011-10-10 10:13:12 +02002436 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2437 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002438
2439 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2440
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002441 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002442 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002443 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002444 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002445 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002446 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002447 wlvif->band = conf->channel->band;
2448 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002449
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002450 if (!is_ap) {
2451 /*
2452 * FIXME: the mac80211 should really provide a fixed
2453 * rate to use here. for now, just use the smallest
2454 * possible rate for the band as a fixed rate for
2455 * association frames and other control messages.
2456 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002457 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002458 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002459
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002460 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002461 wl1271_tx_min_rate_get(wl,
2462 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002463 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002464 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002465 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002466 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002467
Eliad Pellerba8447f2011-10-10 10:13:00 +02002468 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2469 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002470 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002471 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002472 ret = wl12xx_croc(wl,
2473 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002474 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002475 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002476 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002477 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002478 if (ret < 0)
2479 wl1271_warning("cmd join on channel "
2480 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002481 } else {
2482 /*
2483 * change the ROC channel. do it only if we are
2484 * not idle. otherwise, CROC will be called
2485 * anyway.
2486 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002487 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002488 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002489 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002490 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002491 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002492
Eliad Peller679a6732011-10-11 11:55:44 +02002493 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002494 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002495 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002496 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002497 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002498 }
2499 }
2500
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002501 /*
2502 * if mac80211 changes the PSM mode, make sure the mode is not
2503 * incorrectly changed after the pspoll failure active window.
2504 */
2505 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002506 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002507
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002508 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002509 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2510 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002511
2512 /*
2513 * We enter PSM only if we're already associated.
2514 * If we're not, we'll enter it when joining an SSID,
2515 * through the bss_info_changed() hook.
2516 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002517 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002518 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002519 ret = wl1271_ps_set_mode(wl, wlvif,
2520 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002521 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002522 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002523 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002524 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002525 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002526
Eliad Pellerc29bb002011-10-10 10:13:03 +02002527 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002528
Eliad Pellerc29bb002011-10-10 10:13:03 +02002529 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002530 ret = wl1271_ps_set_mode(wl, wlvif,
2531 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002532 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002533 }
2534
Eliad Peller6bd65022011-10-10 10:13:11 +02002535 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002536 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002537 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002538 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002539
Eliad Peller6bd65022011-10-10 10:13:11 +02002540 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002541 }
2542
Eliad Peller9f259c42011-10-10 10:13:12 +02002543 return 0;
2544}
2545
2546static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2547{
2548 struct wl1271 *wl = hw->priv;
2549 struct wl12xx_vif *wlvif;
2550 struct ieee80211_conf *conf = &hw->conf;
2551 int channel, ret = 0;
2552
2553 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2554
2555 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2556 " changed 0x%x",
2557 channel,
2558 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2559 conf->power_level,
2560 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2561 changed);
2562
2563 /*
2564 * mac80211 will go to idle nearly immediately after transmitting some
2565 * frames, such as the deauth. To make sure those frames reach the air,
2566 * wait here until the TX queue is fully flushed.
2567 */
2568 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2569 (conf->flags & IEEE80211_CONF_IDLE))
2570 wl1271_tx_flush(wl);
2571
2572 mutex_lock(&wl->mutex);
2573
2574 /* we support configuring the channel and band even while off */
2575 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2576 wl->band = conf->channel->band;
2577 wl->channel = channel;
2578 }
2579
2580 if (changed & IEEE80211_CONF_CHANGE_POWER)
2581 wl->power_level = conf->power_level;
2582
2583 if (unlikely(wl->state == WL1271_STATE_OFF))
2584 goto out;
2585
2586 ret = wl1271_ps_elp_wakeup(wl);
2587 if (ret < 0)
2588 goto out;
2589
2590 /* configure each interface */
2591 wl12xx_for_each_wlvif(wl, wlvif) {
2592 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2593 if (ret < 0)
2594 goto out_sleep;
2595 }
2596
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002597out_sleep:
2598 wl1271_ps_elp_sleep(wl);
2599
2600out:
2601 mutex_unlock(&wl->mutex);
2602
2603 return ret;
2604}
2605
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002606struct wl1271_filter_params {
2607 bool enabled;
2608 int mc_list_length;
2609 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2610};
2611
Jiri Pirko22bedad2010-04-01 21:22:57 +00002612static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2613 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002614{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002615 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002616 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002617 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002618
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002619 if (unlikely(wl->state == WL1271_STATE_OFF))
2620 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002621
Juuso Oikarinen74441132009-10-13 12:47:53 +03002622 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002623 if (!fp) {
2624 wl1271_error("Out of memory setting filters.");
2625 return 0;
2626 }
2627
2628 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002629 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002630 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2631 fp->enabled = false;
2632 } else {
2633 fp->enabled = true;
2634 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002635 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002636 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002637 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002638 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002639 }
2640
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002641 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002642}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002643
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002644#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2645 FIF_ALLMULTI | \
2646 FIF_FCSFAIL | \
2647 FIF_BCN_PRBRESP_PROMISC | \
2648 FIF_CONTROL | \
2649 FIF_OTHER_BSS)
2650
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002651static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2652 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002653 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002654{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002655 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002656 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002657 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002658
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002659 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002660
Arik Nemtsov7d057862010-10-16 19:25:35 +02002661 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2662 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002663
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002664 mutex_lock(&wl->mutex);
2665
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002666 *total &= WL1271_SUPPORTED_FILTERS;
2667 changed &= WL1271_SUPPORTED_FILTERS;
2668
2669 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002670 goto out;
2671
Ido Yariva6208652011-03-01 15:14:41 +02002672 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002673 if (ret < 0)
2674 goto out;
2675
Eliad Peller6e8cd332011-10-10 10:13:13 +02002676 wl12xx_for_each_wlvif(wl, wlvif) {
2677 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2678 if (*total & FIF_ALLMULTI)
2679 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2680 false,
2681 NULL, 0);
2682 else if (fp)
2683 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2684 fp->enabled,
2685 fp->mc_list,
2686 fp->mc_list_length);
2687 if (ret < 0)
2688 goto out_sleep;
2689 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002690 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002691
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002692 /*
2693 * the fw doesn't provide an api to configure the filters. instead,
2694 * the filters configuration is based on the active roles / ROC
2695 * state.
2696 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002697
2698out_sleep:
2699 wl1271_ps_elp_sleep(wl);
2700
2701out:
2702 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002703 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002704}
2705
Eliad Peller170d0e62011-10-05 11:56:06 +02002706static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2707 u8 id, u8 key_type, u8 key_size,
2708 const u8 *key, u8 hlid, u32 tx_seq_32,
2709 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002710{
2711 struct wl1271_ap_key *ap_key;
2712 int i;
2713
2714 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2715
2716 if (key_size > MAX_KEY_SIZE)
2717 return -EINVAL;
2718
2719 /*
2720 * Find next free entry in ap_keys. Also check we are not replacing
2721 * an existing key.
2722 */
2723 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002724 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002725 break;
2726
Eliad Peller170d0e62011-10-05 11:56:06 +02002727 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002728 wl1271_warning("trying to record key replacement");
2729 return -EINVAL;
2730 }
2731 }
2732
2733 if (i == MAX_NUM_KEYS)
2734 return -EBUSY;
2735
2736 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2737 if (!ap_key)
2738 return -ENOMEM;
2739
2740 ap_key->id = id;
2741 ap_key->key_type = key_type;
2742 ap_key->key_size = key_size;
2743 memcpy(ap_key->key, key, key_size);
2744 ap_key->hlid = hlid;
2745 ap_key->tx_seq_32 = tx_seq_32;
2746 ap_key->tx_seq_16 = tx_seq_16;
2747
Eliad Peller170d0e62011-10-05 11:56:06 +02002748 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002749 return 0;
2750}
2751
Eliad Peller170d0e62011-10-05 11:56:06 +02002752static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002753{
2754 int i;
2755
2756 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002757 kfree(wlvif->ap.recorded_keys[i]);
2758 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002759 }
2760}
2761
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002762static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002763{
2764 int i, ret = 0;
2765 struct wl1271_ap_key *key;
2766 bool wep_key_added = false;
2767
2768 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002769 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002770 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002771 break;
2772
Eliad Peller170d0e62011-10-05 11:56:06 +02002773 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002774 hlid = key->hlid;
2775 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002776 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002777
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002778 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002779 key->id, key->key_type,
2780 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002781 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002782 key->tx_seq_16);
2783 if (ret < 0)
2784 goto out;
2785
2786 if (key->key_type == KEY_WEP)
2787 wep_key_added = true;
2788 }
2789
2790 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002791 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002792 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002793 if (ret < 0)
2794 goto out;
2795 }
2796
2797out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002798 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002799 return ret;
2800}
2801
Eliad Peller536129c2011-10-05 11:55:45 +02002802static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2803 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002804 u8 key_size, const u8 *key, u32 tx_seq_32,
2805 u16 tx_seq_16, struct ieee80211_sta *sta)
2806{
2807 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002808 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002809
2810 if (is_ap) {
2811 struct wl1271_station *wl_sta;
2812 u8 hlid;
2813
2814 if (sta) {
2815 wl_sta = (struct wl1271_station *)sta->drv_priv;
2816 hlid = wl_sta->hlid;
2817 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002818 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002819 }
2820
Eliad Peller53d40d02011-10-10 10:13:02 +02002821 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002822 /*
2823 * We do not support removing keys after AP shutdown.
2824 * Pretend we do to make mac80211 happy.
2825 */
2826 if (action != KEY_ADD_OR_REPLACE)
2827 return 0;
2828
Eliad Peller170d0e62011-10-05 11:56:06 +02002829 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002830 key_type, key_size,
2831 key, hlid, tx_seq_32,
2832 tx_seq_16);
2833 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002834 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002835 id, key_type, key_size,
2836 key, hlid, tx_seq_32,
2837 tx_seq_16);
2838 }
2839
2840 if (ret < 0)
2841 return ret;
2842 } else {
2843 const u8 *addr;
2844 static const u8 bcast_addr[ETH_ALEN] = {
2845 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2846 };
2847
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002848 /*
2849 * A STA set to GEM cipher requires 2 tx spare blocks.
2850 * Return to default value when GEM cipher key is removed
2851 */
2852 if (key_type == KEY_GEM) {
2853 if (action == KEY_ADD_OR_REPLACE)
2854 wl->tx_spare_blocks = 2;
2855 else if (action == KEY_REMOVE)
2856 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2857 }
2858
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002859 addr = sta ? sta->addr : bcast_addr;
2860
2861 if (is_zero_ether_addr(addr)) {
2862 /* We dont support TX only encryption */
2863 return -EOPNOTSUPP;
2864 }
2865
2866 /* The wl1271 does not allow to remove unicast keys - they
2867 will be cleared automatically on next CMD_JOIN. Ignore the
2868 request silently, as we dont want the mac80211 to emit
2869 an error message. */
2870 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2871 return 0;
2872
Eliad Peller010d3d32011-08-14 13:17:31 +03002873 /* don't remove key if hlid was already deleted */
2874 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002875 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002876 return 0;
2877
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002878 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002879 id, key_type, key_size,
2880 key, addr, tx_seq_32,
2881 tx_seq_16);
2882 if (ret < 0)
2883 return ret;
2884
2885 /* the default WEP key needs to be configured at least once */
2886 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002887 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002888 wlvif->default_key,
2889 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002890 if (ret < 0)
2891 return ret;
2892 }
2893 }
2894
2895 return 0;
2896}
2897
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002898static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2899 struct ieee80211_vif *vif,
2900 struct ieee80211_sta *sta,
2901 struct ieee80211_key_conf *key_conf)
2902{
2903 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002904 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002905 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002906 u32 tx_seq_32 = 0;
2907 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002908 u8 key_type;
2909
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002910 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2911
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002912 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002913 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002914 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002915 key_conf->keylen, key_conf->flags);
2916 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2917
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002918 mutex_lock(&wl->mutex);
2919
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002920 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2921 ret = -EAGAIN;
2922 goto out_unlock;
2923 }
2924
Ido Yariva6208652011-03-01 15:14:41 +02002925 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002926 if (ret < 0)
2927 goto out_unlock;
2928
Johannes Berg97359d12010-08-10 09:46:38 +02002929 switch (key_conf->cipher) {
2930 case WLAN_CIPHER_SUITE_WEP40:
2931 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002932 key_type = KEY_WEP;
2933
2934 key_conf->hw_key_idx = key_conf->keyidx;
2935 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002936 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002937 key_type = KEY_TKIP;
2938
2939 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002940 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2941 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002942 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002943 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002944 key_type = KEY_AES;
2945
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002946 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002947 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2948 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002949 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002950 case WL1271_CIPHER_SUITE_GEM:
2951 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002952 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2953 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002954 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002955 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002956 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002957
2958 ret = -EOPNOTSUPP;
2959 goto out_sleep;
2960 }
2961
2962 switch (cmd) {
2963 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002964 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002965 key_conf->keyidx, key_type,
2966 key_conf->keylen, key_conf->key,
2967 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002968 if (ret < 0) {
2969 wl1271_error("Could not add or replace key");
2970 goto out_sleep;
2971 }
2972 break;
2973
2974 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002975 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002976 key_conf->keyidx, key_type,
2977 key_conf->keylen, key_conf->key,
2978 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002979 if (ret < 0) {
2980 wl1271_error("Could not remove key");
2981 goto out_sleep;
2982 }
2983 break;
2984
2985 default:
2986 wl1271_error("Unsupported key cmd 0x%x", cmd);
2987 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002988 break;
2989 }
2990
2991out_sleep:
2992 wl1271_ps_elp_sleep(wl);
2993
2994out_unlock:
2995 mutex_unlock(&wl->mutex);
2996
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002997 return ret;
2998}
2999
3000static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003001 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003002 struct cfg80211_scan_request *req)
3003{
3004 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003005 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3006
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003007 int ret;
3008 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003009 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003010
3011 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3012
3013 if (req->n_ssids) {
3014 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003015 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003016 }
3017
3018 mutex_lock(&wl->mutex);
3019
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003020 if (wl->state == WL1271_STATE_OFF) {
3021 /*
3022 * We cannot return -EBUSY here because cfg80211 will expect
3023 * a call to ieee80211_scan_completed if we do - in this case
3024 * there won't be any call.
3025 */
3026 ret = -EAGAIN;
3027 goto out;
3028 }
3029
Ido Yariva6208652011-03-01 15:14:41 +02003030 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003031 if (ret < 0)
3032 goto out;
3033
Eliad Peller92e712d2011-12-18 20:25:43 +02003034 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
3035 test_bit(wlvif->role_id, wl->roc_map)) {
3036 /* don't allow scanning right now */
3037 ret = -EBUSY;
3038 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003039 }
3040
Eliad Peller92e712d2011-12-18 20:25:43 +02003041 /* cancel ROC before scanning */
3042 if (wl12xx_dev_role_started(wlvif))
3043 wl12xx_stop_dev(wl, wlvif);
3044
Eliad Peller784f6942011-10-05 11:55:39 +02003045 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003046out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003047 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003048out:
3049 mutex_unlock(&wl->mutex);
3050
3051 return ret;
3052}
3053
Eliad Peller73ecce32011-06-27 13:06:45 +03003054static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3055 struct ieee80211_vif *vif)
3056{
3057 struct wl1271 *wl = hw->priv;
3058 int ret;
3059
3060 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3061
3062 mutex_lock(&wl->mutex);
3063
3064 if (wl->state == WL1271_STATE_OFF)
3065 goto out;
3066
3067 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3068 goto out;
3069
3070 ret = wl1271_ps_elp_wakeup(wl);
3071 if (ret < 0)
3072 goto out;
3073
3074 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3075 ret = wl1271_scan_stop(wl);
3076 if (ret < 0)
3077 goto out_sleep;
3078 }
3079 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3080 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003081 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003082 wl->scan.req = NULL;
3083 ieee80211_scan_completed(wl->hw, true);
3084
3085out_sleep:
3086 wl1271_ps_elp_sleep(wl);
3087out:
3088 mutex_unlock(&wl->mutex);
3089
3090 cancel_delayed_work_sync(&wl->scan_complete_work);
3091}
3092
Luciano Coelho33c2c062011-05-10 14:46:02 +03003093static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3094 struct ieee80211_vif *vif,
3095 struct cfg80211_sched_scan_request *req,
3096 struct ieee80211_sched_scan_ies *ies)
3097{
3098 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003099 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003100 int ret;
3101
3102 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3103
3104 mutex_lock(&wl->mutex);
3105
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003106 if (wl->state == WL1271_STATE_OFF) {
3107 ret = -EAGAIN;
3108 goto out;
3109 }
3110
Luciano Coelho33c2c062011-05-10 14:46:02 +03003111 ret = wl1271_ps_elp_wakeup(wl);
3112 if (ret < 0)
3113 goto out;
3114
Eliad Peller536129c2011-10-05 11:55:45 +02003115 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003116 if (ret < 0)
3117 goto out_sleep;
3118
Eliad Peller536129c2011-10-05 11:55:45 +02003119 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003120 if (ret < 0)
3121 goto out_sleep;
3122
3123 wl->sched_scanning = true;
3124
3125out_sleep:
3126 wl1271_ps_elp_sleep(wl);
3127out:
3128 mutex_unlock(&wl->mutex);
3129 return ret;
3130}
3131
3132static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3133 struct ieee80211_vif *vif)
3134{
3135 struct wl1271 *wl = hw->priv;
3136 int ret;
3137
3138 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3139
3140 mutex_lock(&wl->mutex);
3141
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003142 if (wl->state == WL1271_STATE_OFF)
3143 goto out;
3144
Luciano Coelho33c2c062011-05-10 14:46:02 +03003145 ret = wl1271_ps_elp_wakeup(wl);
3146 if (ret < 0)
3147 goto out;
3148
3149 wl1271_scan_sched_scan_stop(wl);
3150
3151 wl1271_ps_elp_sleep(wl);
3152out:
3153 mutex_unlock(&wl->mutex);
3154}
3155
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003156static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3157{
3158 struct wl1271 *wl = hw->priv;
3159 int ret = 0;
3160
3161 mutex_lock(&wl->mutex);
3162
3163 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3164 ret = -EAGAIN;
3165 goto out;
3166 }
3167
Ido Yariva6208652011-03-01 15:14:41 +02003168 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003169 if (ret < 0)
3170 goto out;
3171
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003172 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003173 if (ret < 0)
3174 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3175
3176 wl1271_ps_elp_sleep(wl);
3177
3178out:
3179 mutex_unlock(&wl->mutex);
3180
3181 return ret;
3182}
3183
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003184static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3185{
3186 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003187 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003188 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003189
3190 mutex_lock(&wl->mutex);
3191
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003192 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3193 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003194 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003195 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003196
Ido Yariva6208652011-03-01 15:14:41 +02003197 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003198 if (ret < 0)
3199 goto out;
3200
Eliad Peller6e8cd332011-10-10 10:13:13 +02003201 wl12xx_for_each_wlvif(wl, wlvif) {
3202 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3203 if (ret < 0)
3204 wl1271_warning("set rts threshold failed: %d", ret);
3205 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003206 wl1271_ps_elp_sleep(wl);
3207
3208out:
3209 mutex_unlock(&wl->mutex);
3210
3211 return ret;
3212}
3213
Eliad Peller1fe9f162011-10-05 11:55:48 +02003214static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003215 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003216{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003217 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003218 u8 ssid_len;
3219 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3220 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003221
Eliad Peller889cb362011-05-01 09:56:45 +03003222 if (!ptr) {
3223 wl1271_error("No SSID in IEs!");
3224 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003225 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003226
Eliad Peller889cb362011-05-01 09:56:45 +03003227 ssid_len = ptr[1];
3228 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3229 wl1271_error("SSID is too long!");
3230 return -EINVAL;
3231 }
3232
Eliad Peller1fe9f162011-10-05 11:55:48 +02003233 wlvif->ssid_len = ssid_len;
3234 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003235 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003236}
3237
Eliad Pellerd48055d2011-09-15 12:07:04 +03003238static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3239{
3240 int len;
3241 const u8 *next, *end = skb->data + skb->len;
3242 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3243 skb->len - ieoffset);
3244 if (!ie)
3245 return;
3246 len = ie[1] + 2;
3247 next = ie + len;
3248 memmove(ie, next, end - next);
3249 skb_trim(skb, skb->len - len);
3250}
3251
Eliad Peller26b4bf22011-09-15 12:07:05 +03003252static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3253 unsigned int oui, u8 oui_type,
3254 int ieoffset)
3255{
3256 int len;
3257 const u8 *next, *end = skb->data + skb->len;
3258 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3259 skb->data + ieoffset,
3260 skb->len - ieoffset);
3261 if (!ie)
3262 return;
3263 len = ie[1] + 2;
3264 next = ie + len;
3265 memmove(ie, next, end - next);
3266 skb_trim(skb, skb->len - len);
3267}
3268
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003269static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3270 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003271{
3272 struct sk_buff *skb;
3273 int ret;
3274
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003275 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003276 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003277 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003278
3279 ret = wl1271_cmd_template_set(wl,
3280 CMD_TEMPL_AP_PROBE_RESPONSE,
3281 skb->data,
3282 skb->len, 0,
3283 rates);
3284
3285 dev_kfree_skb(skb);
3286 return ret;
3287}
3288
3289static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3290 struct ieee80211_vif *vif,
3291 u8 *probe_rsp_data,
3292 size_t probe_rsp_len,
3293 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003294{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003295 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3296 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003297 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3298 int ssid_ie_offset, ie_offset, templ_len;
3299 const u8 *ptr;
3300
3301 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003302 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003303 return wl1271_cmd_template_set(wl,
3304 CMD_TEMPL_AP_PROBE_RESPONSE,
3305 probe_rsp_data,
3306 probe_rsp_len, 0,
3307 rates);
3308
3309 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3310 wl1271_error("probe_rsp template too big");
3311 return -EINVAL;
3312 }
3313
3314 /* start searching from IE offset */
3315 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3316
3317 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3318 probe_rsp_len - ie_offset);
3319 if (!ptr) {
3320 wl1271_error("No SSID in beacon!");
3321 return -EINVAL;
3322 }
3323
3324 ssid_ie_offset = ptr - probe_rsp_data;
3325 ptr += (ptr[1] + 2);
3326
3327 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3328
3329 /* insert SSID from bss_conf */
3330 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3331 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3332 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3333 bss_conf->ssid, bss_conf->ssid_len);
3334 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3335
3336 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3337 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3338 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3339
3340 return wl1271_cmd_template_set(wl,
3341 CMD_TEMPL_AP_PROBE_RESPONSE,
3342 probe_rsp_templ,
3343 templ_len, 0,
3344 rates);
3345}
3346
Arik Nemtsove78a2872010-10-16 19:07:21 +02003347static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003348 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003349 struct ieee80211_bss_conf *bss_conf,
3350 u32 changed)
3351{
Eliad Peller0603d892011-10-05 11:55:51 +02003352 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003353 int ret = 0;
3354
3355 if (changed & BSS_CHANGED_ERP_SLOT) {
3356 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003357 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003358 else
Eliad Peller0603d892011-10-05 11:55:51 +02003359 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003360 if (ret < 0) {
3361 wl1271_warning("Set slot time failed %d", ret);
3362 goto out;
3363 }
3364 }
3365
3366 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3367 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003368 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003369 else
Eliad Peller0603d892011-10-05 11:55:51 +02003370 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003371 }
3372
3373 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3374 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003375 ret = wl1271_acx_cts_protect(wl, wlvif,
3376 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003377 else
Eliad Peller0603d892011-10-05 11:55:51 +02003378 ret = wl1271_acx_cts_protect(wl, wlvif,
3379 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003380 if (ret < 0) {
3381 wl1271_warning("Set ctsprotect failed %d", ret);
3382 goto out;
3383 }
3384 }
3385
3386out:
3387 return ret;
3388}
3389
3390static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3391 struct ieee80211_vif *vif,
3392 struct ieee80211_bss_conf *bss_conf,
3393 u32 changed)
3394{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003395 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003396 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003397 int ret = 0;
3398
3399 if ((changed & BSS_CHANGED_BEACON_INT)) {
3400 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3401 bss_conf->beacon_int);
3402
Eliad Peller6a899792011-10-05 11:55:58 +02003403 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003404 }
3405
Arik Nemtsov560f0022011-11-08 18:46:54 +02003406 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3407 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003408 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3409 wl1271_debug(DEBUG_AP, "probe response updated");
3410 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3411 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003412 }
3413
Arik Nemtsove78a2872010-10-16 19:07:21 +02003414 if ((changed & BSS_CHANGED_BEACON)) {
3415 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003416 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003417 int ieoffset = offsetof(struct ieee80211_mgmt,
3418 u.beacon.variable);
3419 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3420 u16 tmpl_id;
3421
Arik Nemtsov560f0022011-11-08 18:46:54 +02003422 if (!beacon) {
3423 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003424 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003425 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003426
3427 wl1271_debug(DEBUG_MASTER, "beacon updated");
3428
Eliad Peller1fe9f162011-10-05 11:55:48 +02003429 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003430 if (ret < 0) {
3431 dev_kfree_skb(beacon);
3432 goto out;
3433 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003434 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003435 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3436 CMD_TEMPL_BEACON;
3437 ret = wl1271_cmd_template_set(wl, tmpl_id,
3438 beacon->data,
3439 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003440 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003441 if (ret < 0) {
3442 dev_kfree_skb(beacon);
3443 goto out;
3444 }
3445
Arik Nemtsov560f0022011-11-08 18:46:54 +02003446 /*
3447 * In case we already have a probe-resp beacon set explicitly
3448 * by usermode, don't use the beacon data.
3449 */
3450 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3451 goto end_bcn;
3452
Eliad Pellerd48055d2011-09-15 12:07:04 +03003453 /* remove TIM ie from probe response */
3454 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3455
Eliad Peller26b4bf22011-09-15 12:07:05 +03003456 /*
3457 * remove p2p ie from probe response.
3458 * the fw reponds to probe requests that don't include
3459 * the p2p ie. probe requests with p2p ie will be passed,
3460 * and will be responded by the supplicant (the spec
3461 * forbids including the p2p ie when responding to probe
3462 * requests that didn't include it).
3463 */
3464 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3465 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3466
Arik Nemtsove78a2872010-10-16 19:07:21 +02003467 hdr = (struct ieee80211_hdr *) beacon->data;
3468 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3469 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003470 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003471 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003472 beacon->data,
3473 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003474 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003475 else
3476 ret = wl1271_cmd_template_set(wl,
3477 CMD_TEMPL_PROBE_RESPONSE,
3478 beacon->data,
3479 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003480 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003481end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003482 dev_kfree_skb(beacon);
3483 if (ret < 0)
3484 goto out;
3485 }
3486
3487out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003488 if (ret != 0)
3489 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003490 return ret;
3491}
3492
3493/* AP mode changes */
3494static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003495 struct ieee80211_vif *vif,
3496 struct ieee80211_bss_conf *bss_conf,
3497 u32 changed)
3498{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003499 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003500 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003501
Arik Nemtsove78a2872010-10-16 19:07:21 +02003502 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3503 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003504
Eliad Peller87fbcb02011-10-05 11:55:41 +02003505 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003506 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003507 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003508 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003509
Eliad Peller87fbcb02011-10-05 11:55:41 +02003510 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003511 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003512 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003513 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003514 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003515
Eliad Peller784f6942011-10-05 11:55:39 +02003516 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003517 if (ret < 0)
3518 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003519 }
3520
Arik Nemtsove78a2872010-10-16 19:07:21 +02003521 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3522 if (ret < 0)
3523 goto out;
3524
3525 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3526 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003527 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003528 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003529 if (ret < 0)
3530 goto out;
3531
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003532 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003533 if (ret < 0)
3534 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003535
Eliad Peller53d40d02011-10-10 10:13:02 +02003536 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003537 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003538 }
3539 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003540 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003541 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003542 if (ret < 0)
3543 goto out;
3544
Eliad Peller53d40d02011-10-10 10:13:02 +02003545 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003546 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3547 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003548 wl1271_debug(DEBUG_AP, "stopped AP");
3549 }
3550 }
3551 }
3552
Eliad Peller0603d892011-10-05 11:55:51 +02003553 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003554 if (ret < 0)
3555 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003556
3557 /* Handle HT information change */
3558 if ((changed & BSS_CHANGED_HT) &&
3559 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003560 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003561 bss_conf->ht_operation_mode);
3562 if (ret < 0) {
3563 wl1271_warning("Set ht information failed %d", ret);
3564 goto out;
3565 }
3566 }
3567
Arik Nemtsove78a2872010-10-16 19:07:21 +02003568out:
3569 return;
3570}
3571
3572/* STA/IBSS mode changes */
3573static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3574 struct ieee80211_vif *vif,
3575 struct ieee80211_bss_conf *bss_conf,
3576 u32 changed)
3577{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003578 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003579 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003580 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003581 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003582 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003583 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003584 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003585 bool sta_exists = false;
3586 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003587
3588 if (is_ibss) {
3589 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3590 changed);
3591 if (ret < 0)
3592 goto out;
3593 }
3594
Eliad Peller227e81e2011-08-14 13:17:26 +03003595 if (changed & BSS_CHANGED_IBSS) {
3596 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003597 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003598 ibss_joined = true;
3599 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003600 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3601 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003602 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003603 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003604 }
3605 }
3606 }
3607
3608 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003609 do_join = true;
3610
3611 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003612 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003613 do_join = true;
3614
Eliad Peller227e81e2011-08-14 13:17:26 +03003615 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003616 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3617 bss_conf->enable_beacon ? "enabled" : "disabled");
3618
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003619 do_join = true;
3620 }
3621
Eliad Pellerc31e4942011-10-23 08:21:55 +02003622 if (changed & BSS_CHANGED_IDLE) {
3623 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3624 if (ret < 0)
3625 wl1271_warning("idle mode change failed %d", ret);
3626 }
3627
Arik Nemtsove78a2872010-10-16 19:07:21 +02003628 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003629 bool enable = false;
3630 if (bss_conf->cqm_rssi_thold)
3631 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003632 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003633 bss_conf->cqm_rssi_thold,
3634 bss_conf->cqm_rssi_hyst);
3635 if (ret < 0)
3636 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003637 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003638 }
3639
Eliad Pellercdf09492011-10-05 11:55:44 +02003640 if (changed & BSS_CHANGED_BSSID)
3641 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003642 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003643 if (ret < 0)
3644 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003645
Eliad Peller784f6942011-10-05 11:55:39 +02003646 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003647 if (ret < 0)
3648 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003649
Eliad Pellerfa287b82010-12-26 09:27:50 +01003650 /* Need to update the BSSID (for filtering etc) */
3651 do_join = true;
3652 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003653
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003654 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3655 rcu_read_lock();
3656 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3657 if (!sta)
3658 goto sta_not_found;
3659
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003660 /* save the supp_rates of the ap */
3661 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3662 if (sta->ht_cap.ht_supported)
3663 sta_rate_set |=
3664 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003665 sta_ht_cap = sta->ht_cap;
3666 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003667
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003668sta_not_found:
3669 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003670 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003671
Arik Nemtsove78a2872010-10-16 19:07:21 +02003672 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003673 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003674 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003675 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003676 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003677 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003678
Eliad Peller74ec8392011-10-05 11:56:02 +02003679 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003680
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003681 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003682 * use basic rates from AP, and determine lowest rate
3683 * to use with control frames.
3684 */
3685 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003686 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003687 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003688 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003689 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003690 wl1271_tx_min_rate_get(wl,
3691 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003692 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003693 wlvif->rate_set =
3694 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003695 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003696 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003697 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003698 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003699 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003700
3701 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003702 * with wl1271, we don't need to update the
3703 * beacon_int and dtim_period, because the firmware
3704 * updates it by itself when the first beacon is
3705 * received after a join.
3706 */
Eliad Peller6840e372011-10-05 11:55:50 +02003707 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003708 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003709 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003710
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003711 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003712 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003713 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003714 dev_kfree_skb(wlvif->probereq);
3715 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003716 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003717 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003718 ieoffset = offsetof(struct ieee80211_mgmt,
3719 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003720 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003721
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003722 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003723 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003724 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003725 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003726 } else {
3727 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003728 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003729 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3730 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003731 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003732 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3733 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003734 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003735
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003736 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003737 dev_kfree_skb(wlvif->probereq);
3738 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003739
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003740 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003741 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003742
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003743 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003744 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003745 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003746 wl1271_tx_min_rate_get(wl,
3747 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003748 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003749 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003750 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003751
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003752 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003753 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003754
3755 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003756 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003757 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003758 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003759
3760 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003761 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003762 u32 conf_flags = wl->hw->conf.flags;
3763 /*
3764 * we might have to disable roc, if there was
3765 * no IF_OPER_UP notification.
3766 */
3767 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003768 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003769 if (ret < 0)
3770 goto out;
3771 }
3772 /*
3773 * (we also need to disable roc in case of
3774 * roaming on the same channel. until we will
3775 * have a better flow...)
3776 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003777 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3778 ret = wl12xx_croc(wl,
3779 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003780 if (ret < 0)
3781 goto out;
3782 }
3783
Eliad Peller0603d892011-10-05 11:55:51 +02003784 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003785 if (!(conf_flags & IEEE80211_CONF_IDLE))
3786 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003787 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003788 }
3789 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003790
Eliad Pellerd192d262011-05-24 14:33:08 +03003791 if (changed & BSS_CHANGED_IBSS) {
3792 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3793 bss_conf->ibss_joined);
3794
3795 if (bss_conf->ibss_joined) {
3796 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003797 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003798 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003799 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003800 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003801 wl1271_tx_min_rate_get(wl,
3802 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003803
Shahar Levi06b660e2011-09-05 13:54:36 +03003804 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003805 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3806 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003807 if (ret < 0)
3808 goto out;
3809 }
3810 }
3811
Eliad Peller0603d892011-10-05 11:55:51 +02003812 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003813 if (ret < 0)
3814 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003815
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003816 if (changed & BSS_CHANGED_ARP_FILTER) {
3817 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003818 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003819
Eliad Pellerc5312772010-12-09 11:31:27 +02003820 if (bss_conf->arp_addr_cnt == 1 &&
3821 bss_conf->arp_filter_enabled) {
3822 /*
3823 * The template should have been configured only upon
3824 * association. however, it seems that the correct ip
3825 * isn't being set (when sending), so we have to
3826 * reconfigure the template upon every ip change.
3827 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003828 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003829 if (ret < 0) {
3830 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003831 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003832 }
3833
Eliad Peller0603d892011-10-05 11:55:51 +02003834 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003835 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003836 addr);
3837 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003838 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003839
3840 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003841 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003842 }
3843
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003844 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003845 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003846 if (ret < 0) {
3847 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003848 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003849 }
Eliad Peller251c1772011-08-14 13:17:17 +03003850
3851 /* ROC until connected (after EAPOL exchange) */
3852 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003853 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003854 if (ret < 0)
3855 goto out;
3856
Eliad Pellerba8447f2011-10-10 10:13:00 +02003857 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003858 ieee80211_get_operstate(vif));
3859 }
3860 /*
3861 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003862 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003863 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003864 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003865 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003866 if (ret < 0)
3867 goto out;
3868 }
Eliad Peller05dba352011-08-23 16:37:01 +03003869
3870 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003871 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3872 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003873 enum wl1271_cmd_ps_mode mode;
3874
3875 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003876 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003877 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003878 true);
3879 if (ret < 0)
3880 goto out;
3881 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003882 }
3883
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003884 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003885 if (sta_exists) {
3886 if ((changed & BSS_CHANGED_HT) &&
3887 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003888 ret = wl1271_acx_set_ht_capabilities(wl,
3889 &sta_ht_cap,
3890 true,
Eliad Peller154da672011-10-05 11:55:53 +02003891 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003892 if (ret < 0) {
3893 wl1271_warning("Set ht cap true failed %d",
3894 ret);
3895 goto out;
3896 }
3897 }
3898 /* handle new association without HT and disassociation */
3899 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003900 ret = wl1271_acx_set_ht_capabilities(wl,
3901 &sta_ht_cap,
3902 false,
Eliad Peller154da672011-10-05 11:55:53 +02003903 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003904 if (ret < 0) {
3905 wl1271_warning("Set ht cap false failed %d",
3906 ret);
3907 goto out;
3908 }
3909 }
3910 }
3911
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003912 /* Handle HT information change. Done after join. */
3913 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003914 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003915 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003916 bss_conf->ht_operation_mode);
3917 if (ret < 0) {
3918 wl1271_warning("Set ht information failed %d", ret);
3919 goto out;
3920 }
3921 }
3922
Arik Nemtsove78a2872010-10-16 19:07:21 +02003923out:
3924 return;
3925}
3926
3927static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3928 struct ieee80211_vif *vif,
3929 struct ieee80211_bss_conf *bss_conf,
3930 u32 changed)
3931{
3932 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003933 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3934 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003935 int ret;
3936
3937 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3938 (int)changed);
3939
3940 mutex_lock(&wl->mutex);
3941
3942 if (unlikely(wl->state == WL1271_STATE_OFF))
3943 goto out;
3944
Eliad Peller10c8cd02011-10-10 10:13:06 +02003945 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3946 goto out;
3947
Ido Yariva6208652011-03-01 15:14:41 +02003948 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003949 if (ret < 0)
3950 goto out;
3951
3952 if (is_ap)
3953 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3954 else
3955 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3956
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003957 wl1271_ps_elp_sleep(wl);
3958
3959out:
3960 mutex_unlock(&wl->mutex);
3961}
3962
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003963static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3964 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003965 const struct ieee80211_tx_queue_params *params)
3966{
3967 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003968 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003969 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003970 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003971
3972 mutex_lock(&wl->mutex);
3973
3974 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3975
Kalle Valo4695dc92010-03-18 12:26:38 +02003976 if (params->uapsd)
3977 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3978 else
3979 ps_scheme = CONF_PS_SCHEME_LEGACY;
3980
Eliad Peller5b37ddf2011-12-18 20:25:40 +02003981 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003982 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003983
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003984 ret = wl1271_ps_elp_wakeup(wl);
3985 if (ret < 0)
3986 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003987
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003988 /*
3989 * the txop is confed in units of 32us by the mac80211,
3990 * we need us
3991 */
Eliad Peller0603d892011-10-05 11:55:51 +02003992 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003993 params->cw_min, params->cw_max,
3994 params->aifs, params->txop << 5);
3995 if (ret < 0)
3996 goto out_sleep;
3997
Eliad Peller0603d892011-10-05 11:55:51 +02003998 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003999 CONF_CHANNEL_TYPE_EDCF,
4000 wl1271_tx_get_queue(queue),
4001 ps_scheme, CONF_ACK_POLICY_LEGACY,
4002 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004003
4004out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004005 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004006
4007out:
4008 mutex_unlock(&wl->mutex);
4009
4010 return ret;
4011}
4012
Eliad Peller37a41b42011-09-21 14:06:11 +03004013static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4014 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004015{
4016
4017 struct wl1271 *wl = hw->priv;
4018 u64 mactime = ULLONG_MAX;
4019 int ret;
4020
4021 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4022
4023 mutex_lock(&wl->mutex);
4024
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004025 if (unlikely(wl->state == WL1271_STATE_OFF))
4026 goto out;
4027
Ido Yariva6208652011-03-01 15:14:41 +02004028 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004029 if (ret < 0)
4030 goto out;
4031
4032 ret = wl1271_acx_tsf_info(wl, &mactime);
4033 if (ret < 0)
4034 goto out_sleep;
4035
4036out_sleep:
4037 wl1271_ps_elp_sleep(wl);
4038
4039out:
4040 mutex_unlock(&wl->mutex);
4041 return mactime;
4042}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004043
John W. Linvilleece550d2010-07-28 16:41:06 -04004044static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4045 struct survey_info *survey)
4046{
4047 struct wl1271 *wl = hw->priv;
4048 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004049
John W. Linvilleece550d2010-07-28 16:41:06 -04004050 if (idx != 0)
4051 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004052
John W. Linvilleece550d2010-07-28 16:41:06 -04004053 survey->channel = conf->channel;
4054 survey->filled = SURVEY_INFO_NOISE_DBM;
4055 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004056
John W. Linvilleece550d2010-07-28 16:41:06 -04004057 return 0;
4058}
4059
Arik Nemtsov409622e2011-02-23 00:22:29 +02004060static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004061 struct wl12xx_vif *wlvif,
4062 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004063{
4064 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004065 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004066
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004067
4068 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004069 wl1271_warning("could not allocate HLID - too much stations");
4070 return -EBUSY;
4071 }
4072
4073 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004074 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4075 if (ret < 0) {
4076 wl1271_warning("could not allocate HLID - too many links");
4077 return -EBUSY;
4078 }
4079
4080 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004081 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004082 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004083 return 0;
4084}
4085
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004086void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004087{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004088 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004089 return;
4090
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004091 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004092 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004093 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004094 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004095 __clear_bit(hlid, &wl->ap_ps_map);
4096 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004097 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004098 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004099}
4100
4101static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4102 struct ieee80211_vif *vif,
4103 struct ieee80211_sta *sta)
4104{
4105 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004106 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004107 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004108 int ret = 0;
4109 u8 hlid;
4110
4111 mutex_lock(&wl->mutex);
4112
4113 if (unlikely(wl->state == WL1271_STATE_OFF))
4114 goto out;
4115
Eliad Peller536129c2011-10-05 11:55:45 +02004116 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004117 goto out;
4118
4119 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4120
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004121 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004122 if (ret < 0)
4123 goto out;
4124
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004125 wl_sta = (struct wl1271_station *)sta->drv_priv;
4126 hlid = wl_sta->hlid;
4127
Ido Yariva6208652011-03-01 15:14:41 +02004128 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004129 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004130 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004131
Eliad Peller1b92f152011-10-10 10:13:09 +02004132 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004133 if (ret < 0)
4134 goto out_sleep;
4135
Eliad Pellerb67476e2011-08-14 13:17:23 +03004136 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4137 if (ret < 0)
4138 goto out_sleep;
4139
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004140 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4141 if (ret < 0)
4142 goto out_sleep;
4143
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004144out_sleep:
4145 wl1271_ps_elp_sleep(wl);
4146
Arik Nemtsov409622e2011-02-23 00:22:29 +02004147out_free_sta:
4148 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004149 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004150
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004151out:
4152 mutex_unlock(&wl->mutex);
4153 return ret;
4154}
4155
4156static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4157 struct ieee80211_vif *vif,
4158 struct ieee80211_sta *sta)
4159{
4160 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004161 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004162 struct wl1271_station *wl_sta;
4163 int ret = 0, id;
4164
4165 mutex_lock(&wl->mutex);
4166
4167 if (unlikely(wl->state == WL1271_STATE_OFF))
4168 goto out;
4169
Eliad Peller536129c2011-10-05 11:55:45 +02004170 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004171 goto out;
4172
4173 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4174
4175 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004176 id = wl_sta->hlid;
4177 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004178 goto out;
4179
Ido Yariva6208652011-03-01 15:14:41 +02004180 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004181 if (ret < 0)
4182 goto out;
4183
Eliad Pellerc690ec82011-08-14 13:17:07 +03004184 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004185 if (ret < 0)
4186 goto out_sleep;
4187
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004188 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004189
4190out_sleep:
4191 wl1271_ps_elp_sleep(wl);
4192
4193out:
4194 mutex_unlock(&wl->mutex);
4195 return ret;
4196}
4197
Luciano Coelho4623ec72011-03-21 19:26:41 +02004198static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4199 struct ieee80211_vif *vif,
4200 enum ieee80211_ampdu_mlme_action action,
4201 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4202 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004203{
4204 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004205 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004206 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004207 u8 hlid, *ba_bitmap;
4208
4209 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4210 tid);
4211
4212 /* sanity check - the fields in FW are only 8bits wide */
4213 if (WARN_ON(tid > 0xFF))
4214 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004215
4216 mutex_lock(&wl->mutex);
4217
4218 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4219 ret = -EAGAIN;
4220 goto out;
4221 }
4222
Eliad Peller536129c2011-10-05 11:55:45 +02004223 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004224 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004225 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004226 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004227 struct wl1271_station *wl_sta;
4228
4229 wl_sta = (struct wl1271_station *)sta->drv_priv;
4230 hlid = wl_sta->hlid;
4231 ba_bitmap = &wl->links[hlid].ba_bitmap;
4232 } else {
4233 ret = -EINVAL;
4234 goto out;
4235 }
4236
Ido Yariva6208652011-03-01 15:14:41 +02004237 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004238 if (ret < 0)
4239 goto out;
4240
Shahar Levi70559a02011-05-22 16:10:22 +03004241 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4242 tid, action);
4243
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004244 switch (action) {
4245 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004246 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004247 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004248 break;
4249 }
4250
4251 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4252 ret = -EBUSY;
4253 wl1271_error("exceeded max RX BA sessions");
4254 break;
4255 }
4256
4257 if (*ba_bitmap & BIT(tid)) {
4258 ret = -EINVAL;
4259 wl1271_error("cannot enable RX BA session on active "
4260 "tid: %d", tid);
4261 break;
4262 }
4263
4264 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4265 hlid);
4266 if (!ret) {
4267 *ba_bitmap |= BIT(tid);
4268 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004269 }
4270 break;
4271
4272 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004273 if (!(*ba_bitmap & BIT(tid))) {
4274 ret = -EINVAL;
4275 wl1271_error("no active RX BA session on tid: %d",
4276 tid);
4277 break;
4278 }
4279
4280 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4281 hlid);
4282 if (!ret) {
4283 *ba_bitmap &= ~BIT(tid);
4284 wl->ba_rx_session_count--;
4285 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004286 break;
4287
4288 /*
4289 * The BA initiator session management in FW independently.
4290 * Falling break here on purpose for all TX APDU commands.
4291 */
4292 case IEEE80211_AMPDU_TX_START:
4293 case IEEE80211_AMPDU_TX_STOP:
4294 case IEEE80211_AMPDU_TX_OPERATIONAL:
4295 ret = -EINVAL;
4296 break;
4297
4298 default:
4299 wl1271_error("Incorrect ampdu action id=%x\n", action);
4300 ret = -EINVAL;
4301 }
4302
4303 wl1271_ps_elp_sleep(wl);
4304
4305out:
4306 mutex_unlock(&wl->mutex);
4307
4308 return ret;
4309}
4310
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004311static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4312 struct ieee80211_vif *vif,
4313 const struct cfg80211_bitrate_mask *mask)
4314{
Eliad Peller83587502011-10-10 10:12:53 +02004315 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004316 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004317 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004318
4319 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4320 mask->control[NL80211_BAND_2GHZ].legacy,
4321 mask->control[NL80211_BAND_5GHZ].legacy);
4322
4323 mutex_lock(&wl->mutex);
4324
4325 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004326 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004327 wl1271_tx_enabled_rates_get(wl,
4328 mask->control[i].legacy,
4329 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004330
4331 if (unlikely(wl->state == WL1271_STATE_OFF))
4332 goto out;
4333
4334 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4335 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4336
4337 ret = wl1271_ps_elp_wakeup(wl);
4338 if (ret < 0)
4339 goto out;
4340
4341 wl1271_set_band_rate(wl, wlvif);
4342 wlvif->basic_rate =
4343 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4344 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4345
4346 wl1271_ps_elp_sleep(wl);
4347 }
4348out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004349 mutex_unlock(&wl->mutex);
4350
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004351 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004352}
4353
Shahar Levi6d158ff2011-09-08 13:01:33 +03004354static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4355 struct ieee80211_channel_switch *ch_switch)
4356{
4357 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004358 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004359 int ret;
4360
4361 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4362
4363 mutex_lock(&wl->mutex);
4364
4365 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004366 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4367 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4368 ieee80211_chswitch_done(vif, false);
4369 }
4370 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004371 }
4372
4373 ret = wl1271_ps_elp_wakeup(wl);
4374 if (ret < 0)
4375 goto out;
4376
Eliad Peller52630c52011-10-10 10:13:08 +02004377 /* TODO: change mac80211 to pass vif as param */
4378 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4379 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004380
Eliad Peller52630c52011-10-10 10:13:08 +02004381 if (!ret)
4382 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4383 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004384
4385 wl1271_ps_elp_sleep(wl);
4386
4387out:
4388 mutex_unlock(&wl->mutex);
4389}
4390
Arik Nemtsov33437892011-04-26 23:35:39 +03004391static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4392{
4393 struct wl1271 *wl = hw->priv;
4394 bool ret = false;
4395
4396 mutex_lock(&wl->mutex);
4397
4398 if (unlikely(wl->state == WL1271_STATE_OFF))
4399 goto out;
4400
4401 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004402 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004403out:
4404 mutex_unlock(&wl->mutex);
4405
4406 return ret;
4407}
4408
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004409/* can't be const, mac80211 writes to this */
4410static struct ieee80211_rate wl1271_rates[] = {
4411 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004412 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4413 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004414 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004415 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4416 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004417 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4418 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004419 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4420 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004421 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4422 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004423 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4424 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004425 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4426 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004427 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4428 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004429 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004430 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4431 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004432 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004433 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4434 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004435 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004436 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4437 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004438 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004439 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4440 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004441 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004442 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4443 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004444 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004445 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4446 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004447 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004448 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4449 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004450};
4451
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004452/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004453static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004454 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004455 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004456 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4457 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4458 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004459 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004460 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4461 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4462 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004463 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004464 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4465 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4466 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004467 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004468};
4469
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004470/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004471static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004472 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004473 7, /* CONF_HW_RXTX_RATE_MCS7 */
4474 6, /* CONF_HW_RXTX_RATE_MCS6 */
4475 5, /* CONF_HW_RXTX_RATE_MCS5 */
4476 4, /* CONF_HW_RXTX_RATE_MCS4 */
4477 3, /* CONF_HW_RXTX_RATE_MCS3 */
4478 2, /* CONF_HW_RXTX_RATE_MCS2 */
4479 1, /* CONF_HW_RXTX_RATE_MCS1 */
4480 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004481
4482 11, /* CONF_HW_RXTX_RATE_54 */
4483 10, /* CONF_HW_RXTX_RATE_48 */
4484 9, /* CONF_HW_RXTX_RATE_36 */
4485 8, /* CONF_HW_RXTX_RATE_24 */
4486
4487 /* TI-specific rate */
4488 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4489
4490 7, /* CONF_HW_RXTX_RATE_18 */
4491 6, /* CONF_HW_RXTX_RATE_12 */
4492 3, /* CONF_HW_RXTX_RATE_11 */
4493 5, /* CONF_HW_RXTX_RATE_9 */
4494 4, /* CONF_HW_RXTX_RATE_6 */
4495 2, /* CONF_HW_RXTX_RATE_5_5 */
4496 1, /* CONF_HW_RXTX_RATE_2 */
4497 0 /* CONF_HW_RXTX_RATE_1 */
4498};
4499
Shahar Levie8b03a22010-10-13 16:09:39 +02004500/* 11n STA capabilities */
4501#define HW_RX_HIGHEST_RATE 72
4502
Shahar Levi00d20102010-11-08 11:20:10 +00004503#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004504 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4505 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004506 .ht_supported = true, \
4507 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4508 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4509 .mcs = { \
4510 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4511 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4512 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4513 }, \
4514}
4515
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004516/* can't be const, mac80211 writes to this */
4517static struct ieee80211_supported_band wl1271_band_2ghz = {
4518 .channels = wl1271_channels,
4519 .n_channels = ARRAY_SIZE(wl1271_channels),
4520 .bitrates = wl1271_rates,
4521 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004522 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004523};
4524
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004525/* 5 GHz data rates for WL1273 */
4526static struct ieee80211_rate wl1271_rates_5ghz[] = {
4527 { .bitrate = 60,
4528 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4529 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4530 { .bitrate = 90,
4531 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4532 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4533 { .bitrate = 120,
4534 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4535 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4536 { .bitrate = 180,
4537 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4538 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4539 { .bitrate = 240,
4540 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4541 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4542 { .bitrate = 360,
4543 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4544 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4545 { .bitrate = 480,
4546 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4547 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4548 { .bitrate = 540,
4549 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4550 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4551};
4552
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004553/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004554static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004555 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4556 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4557 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4558 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4559 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4560 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4561 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4562 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4563 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4564 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4565 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4566 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4567 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4568 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4569 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4570 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4571 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4572 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4573 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4574 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4575 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4576 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4577 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4578 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4579 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4580 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4581 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4582 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4583 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4584 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4585 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4586 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4587 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4588 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004589};
4590
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004591/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004592static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004593 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004594 7, /* CONF_HW_RXTX_RATE_MCS7 */
4595 6, /* CONF_HW_RXTX_RATE_MCS6 */
4596 5, /* CONF_HW_RXTX_RATE_MCS5 */
4597 4, /* CONF_HW_RXTX_RATE_MCS4 */
4598 3, /* CONF_HW_RXTX_RATE_MCS3 */
4599 2, /* CONF_HW_RXTX_RATE_MCS2 */
4600 1, /* CONF_HW_RXTX_RATE_MCS1 */
4601 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004602
4603 7, /* CONF_HW_RXTX_RATE_54 */
4604 6, /* CONF_HW_RXTX_RATE_48 */
4605 5, /* CONF_HW_RXTX_RATE_36 */
4606 4, /* CONF_HW_RXTX_RATE_24 */
4607
4608 /* TI-specific rate */
4609 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4610
4611 3, /* CONF_HW_RXTX_RATE_18 */
4612 2, /* CONF_HW_RXTX_RATE_12 */
4613 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4614 1, /* CONF_HW_RXTX_RATE_9 */
4615 0, /* CONF_HW_RXTX_RATE_6 */
4616 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4617 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4618 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4619};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004620
4621static struct ieee80211_supported_band wl1271_band_5ghz = {
4622 .channels = wl1271_channels_5ghz,
4623 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4624 .bitrates = wl1271_rates_5ghz,
4625 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004626 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004627};
4628
Tobias Klausera0ea9492010-05-20 10:38:11 +02004629static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004630 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4631 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4632};
4633
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004634static const struct ieee80211_ops wl1271_ops = {
4635 .start = wl1271_op_start,
4636 .stop = wl1271_op_stop,
4637 .add_interface = wl1271_op_add_interface,
4638 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004639 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004640#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004641 .suspend = wl1271_op_suspend,
4642 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004643#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004644 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004645 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004646 .configure_filter = wl1271_op_configure_filter,
4647 .tx = wl1271_op_tx,
4648 .set_key = wl1271_op_set_key,
4649 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004650 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004651 .sched_scan_start = wl1271_op_sched_scan_start,
4652 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004653 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004654 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004655 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004656 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004657 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004658 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004659 .sta_add = wl1271_op_sta_add,
4660 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004661 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004662 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004663 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004664 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004665 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004666};
4667
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004668
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004669u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004670{
4671 u8 idx;
4672
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004673 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004674
4675 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4676 wl1271_error("Illegal RX rate from HW: %d", rate);
4677 return 0;
4678 }
4679
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004680 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004681 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4682 wl1271_error("Unsupported RX rate from HW: %d", rate);
4683 return 0;
4684 }
4685
4686 return idx;
4687}
4688
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004689static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4690 struct device_attribute *attr,
4691 char *buf)
4692{
4693 struct wl1271 *wl = dev_get_drvdata(dev);
4694 ssize_t len;
4695
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004696 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004697
4698 mutex_lock(&wl->mutex);
4699 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4700 wl->sg_enabled);
4701 mutex_unlock(&wl->mutex);
4702
4703 return len;
4704
4705}
4706
4707static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4708 struct device_attribute *attr,
4709 const char *buf, size_t count)
4710{
4711 struct wl1271 *wl = dev_get_drvdata(dev);
4712 unsigned long res;
4713 int ret;
4714
Luciano Coelho6277ed62011-04-01 17:49:54 +03004715 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004716 if (ret < 0) {
4717 wl1271_warning("incorrect value written to bt_coex_mode");
4718 return count;
4719 }
4720
4721 mutex_lock(&wl->mutex);
4722
4723 res = !!res;
4724
4725 if (res == wl->sg_enabled)
4726 goto out;
4727
4728 wl->sg_enabled = res;
4729
4730 if (wl->state == WL1271_STATE_OFF)
4731 goto out;
4732
Ido Yariva6208652011-03-01 15:14:41 +02004733 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004734 if (ret < 0)
4735 goto out;
4736
4737 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4738 wl1271_ps_elp_sleep(wl);
4739
4740 out:
4741 mutex_unlock(&wl->mutex);
4742 return count;
4743}
4744
4745static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4746 wl1271_sysfs_show_bt_coex_state,
4747 wl1271_sysfs_store_bt_coex_state);
4748
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004749static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4750 struct device_attribute *attr,
4751 char *buf)
4752{
4753 struct wl1271 *wl = dev_get_drvdata(dev);
4754 ssize_t len;
4755
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004756 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004757
4758 mutex_lock(&wl->mutex);
4759 if (wl->hw_pg_ver >= 0)
4760 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4761 else
4762 len = snprintf(buf, len, "n/a\n");
4763 mutex_unlock(&wl->mutex);
4764
4765 return len;
4766}
4767
Gery Kahn6f07b722011-07-18 14:21:49 +03004768static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004769 wl1271_sysfs_show_hw_pg_ver, NULL);
4770
Ido Yariv95dac04f2011-06-06 14:57:06 +03004771static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4772 struct bin_attribute *bin_attr,
4773 char *buffer, loff_t pos, size_t count)
4774{
4775 struct device *dev = container_of(kobj, struct device, kobj);
4776 struct wl1271 *wl = dev_get_drvdata(dev);
4777 ssize_t len;
4778 int ret;
4779
4780 ret = mutex_lock_interruptible(&wl->mutex);
4781 if (ret < 0)
4782 return -ERESTARTSYS;
4783
4784 /* Let only one thread read the log at a time, blocking others */
4785 while (wl->fwlog_size == 0) {
4786 DEFINE_WAIT(wait);
4787
4788 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4789 &wait,
4790 TASK_INTERRUPTIBLE);
4791
4792 if (wl->fwlog_size != 0) {
4793 finish_wait(&wl->fwlog_waitq, &wait);
4794 break;
4795 }
4796
4797 mutex_unlock(&wl->mutex);
4798
4799 schedule();
4800 finish_wait(&wl->fwlog_waitq, &wait);
4801
4802 if (signal_pending(current))
4803 return -ERESTARTSYS;
4804
4805 ret = mutex_lock_interruptible(&wl->mutex);
4806 if (ret < 0)
4807 return -ERESTARTSYS;
4808 }
4809
4810 /* Check if the fwlog is still valid */
4811 if (wl->fwlog_size < 0) {
4812 mutex_unlock(&wl->mutex);
4813 return 0;
4814 }
4815
4816 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4817 len = min(count, (size_t)wl->fwlog_size);
4818 wl->fwlog_size -= len;
4819 memcpy(buffer, wl->fwlog, len);
4820
4821 /* Make room for new messages */
4822 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4823
4824 mutex_unlock(&wl->mutex);
4825
4826 return len;
4827}
4828
4829static struct bin_attribute fwlog_attr = {
4830 .attr = {.name = "fwlog", .mode = S_IRUSR},
4831 .read = wl1271_sysfs_read_fwlog,
4832};
4833
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004834static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004835{
4836 int ret;
4837
4838 if (wl->mac80211_registered)
4839 return 0;
4840
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004841 ret = wl1271_fetch_nvs(wl);
4842 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004843 /* NOTE: The wl->nvs->nvs element must be first, in
4844 * order to simplify the casting, we assume it is at
4845 * the beginning of the wl->nvs structure.
4846 */
4847 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004848
4849 wl->mac_addr[0] = nvs_ptr[11];
4850 wl->mac_addr[1] = nvs_ptr[10];
4851 wl->mac_addr[2] = nvs_ptr[6];
4852 wl->mac_addr[3] = nvs_ptr[5];
4853 wl->mac_addr[4] = nvs_ptr[4];
4854 wl->mac_addr[5] = nvs_ptr[3];
4855 }
4856
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004857 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4858
4859 ret = ieee80211_register_hw(wl->hw);
4860 if (ret < 0) {
4861 wl1271_error("unable to register mac80211 hw: %d", ret);
4862 return ret;
4863 }
4864
4865 wl->mac80211_registered = true;
4866
Eliad Pellerd60080a2010-11-24 12:53:16 +02004867 wl1271_debugfs_init(wl);
4868
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004869 register_netdevice_notifier(&wl1271_dev_notifier);
4870
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004871 wl1271_notice("loaded");
4872
4873 return 0;
4874}
4875
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004876static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004877{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004878 if (wl->state == WL1271_STATE_PLT)
Ido Yarivf3df1332012-01-11 09:42:39 +02004879 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004880
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004881 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004882 ieee80211_unregister_hw(wl->hw);
4883 wl->mac80211_registered = false;
4884
4885}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004886
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004887static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004888{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004889 static const u32 cipher_suites[] = {
4890 WLAN_CIPHER_SUITE_WEP40,
4891 WLAN_CIPHER_SUITE_WEP104,
4892 WLAN_CIPHER_SUITE_TKIP,
4893 WLAN_CIPHER_SUITE_CCMP,
4894 WL1271_CIPHER_SUITE_GEM,
4895 };
4896
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004897 /* The tx descriptor buffer and the TKIP space. */
4898 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4899 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004900
4901 /* unit us */
4902 /* FIXME: find a proper value */
4903 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004904 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004905
4906 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004907 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004908 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004909 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004910 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004911 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004912 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004913 IEEE80211_HW_AP_LINK_PS |
4914 IEEE80211_HW_AMPDU_AGGREGATION |
4915 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004916
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004917 wl->hw->wiphy->cipher_suites = cipher_suites;
4918 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4919
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004920 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004921 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4922 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004923 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004924 wl->hw->wiphy->max_sched_scan_ssids = 16;
4925 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004926 /*
4927 * Maximum length of elements in scanning probe request templates
4928 * should be the maximum length possible for a template, without
4929 * the IEEE80211 header of the template
4930 */
Eliad Peller154037d2011-08-14 13:17:12 +03004931 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004932 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004933
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004934 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4935 sizeof(struct ieee80211_header);
4936
Eliad Peller1ec23f72011-08-25 14:26:54 +03004937 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4938
Luciano Coelho4a31c112011-03-21 23:16:14 +02004939 /* make sure all our channels fit in the scanned_ch bitmask */
4940 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4941 ARRAY_SIZE(wl1271_channels_5ghz) >
4942 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004943 /*
4944 * We keep local copies of the band structs because we need to
4945 * modify them on a per-device basis.
4946 */
4947 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4948 sizeof(wl1271_band_2ghz));
4949 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4950 sizeof(wl1271_band_5ghz));
4951
4952 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4953 &wl->bands[IEEE80211_BAND_2GHZ];
4954 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4955 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004956
Kalle Valo12bd8942010-03-18 12:26:33 +02004957 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004958 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004959
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004960 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4961
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02004962 /* the FW answers probe-requests in AP-mode */
4963 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
4964 wl->hw->wiphy->probe_resp_offload =
4965 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
4966 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
4967 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
4968
Felipe Balbia390e852011-10-06 10:07:44 +03004969 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004970
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004971 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004972 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004973
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004974 wl->hw->max_rx_aggregation_subframes = 8;
4975
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004976 return 0;
4977}
4978
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004979#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004980
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004981static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004982{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004983 struct ieee80211_hw *hw;
4984 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004985 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004986 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004987
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004988 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004989
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004990 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4991 if (!hw) {
4992 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004993 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004994 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004995 }
4996
4997 wl = hw->priv;
4998 memset(wl, 0, sizeof(*wl));
4999
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005000 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005001 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005002
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005003 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005004
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005005 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005006 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005007 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5008
Ido Yariva6208652011-03-01 15:14:41 +02005009 skb_queue_head_init(&wl->deferred_rx_queue);
5010 skb_queue_head_init(&wl->deferred_tx_queue);
5011
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005012 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005013 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005014 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5015 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5016 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005017
Eliad Peller92ef8962011-06-07 12:50:46 +03005018 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5019 if (!wl->freezable_wq) {
5020 ret = -ENOMEM;
5021 goto err_hw;
5022 }
5023
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005024 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005025 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005026 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005027 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005028 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005029 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005030 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005031 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005032 wl->ap_ps_map = 0;
5033 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005034 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005035 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005036 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005037 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005038 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005039 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005040 wl->fwlog_size = 0;
5041 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005042
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005043 /* The system link is always allocated */
5044 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5045
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005046 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005047 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005048 wl->tx_frames[i] = NULL;
5049
5050 spin_lock_init(&wl->wl_lock);
5051
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005052 wl->state = WL1271_STATE_OFF;
5053 mutex_init(&wl->mutex);
5054
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005055 /* Apply default driver configuration. */
5056 wl1271_conf_init(wl);
5057
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005058 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5059 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5060 if (!wl->aggr_buf) {
5061 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005062 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005063 }
5064
Ido Yariv990f5de2011-03-31 10:06:59 +02005065 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5066 if (!wl->dummy_packet) {
5067 ret = -ENOMEM;
5068 goto err_aggr;
5069 }
5070
Ido Yariv95dac04f2011-06-06 14:57:06 +03005071 /* Allocate one page for the FW log */
5072 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5073 if (!wl->fwlog) {
5074 ret = -ENOMEM;
5075 goto err_dummy_packet;
5076 }
5077
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005078 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005079
Ido Yariv990f5de2011-03-31 10:06:59 +02005080err_dummy_packet:
5081 dev_kfree_skb(wl->dummy_packet);
5082
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005083err_aggr:
5084 free_pages((unsigned long)wl->aggr_buf, order);
5085
Eliad Peller92ef8962011-06-07 12:50:46 +03005086err_wq:
5087 destroy_workqueue(wl->freezable_wq);
5088
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005089err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005090 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005091 ieee80211_free_hw(hw);
5092
5093err_hw_alloc:
5094
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005095 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005096}
5097
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005098static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005099{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005100 /* Unblock any fwlog readers */
5101 mutex_lock(&wl->mutex);
5102 wl->fwlog_size = -1;
5103 wake_up_interruptible_all(&wl->fwlog_waitq);
5104 mutex_unlock(&wl->mutex);
5105
Felipe Balbif79f8902011-10-06 13:05:25 +03005106 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005107
Felipe Balbif79f8902011-10-06 13:05:25 +03005108 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005109
Felipe Balbif79f8902011-10-06 13:05:25 +03005110 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005111 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005112 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005113 free_pages((unsigned long)wl->aggr_buf,
5114 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005115
5116 wl1271_debugfs_exit(wl);
5117
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005118 vfree(wl->fw);
5119 wl->fw = NULL;
5120 kfree(wl->nvs);
5121 wl->nvs = NULL;
5122
5123 kfree(wl->fw_status);
5124 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005125 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005126
5127 ieee80211_free_hw(wl->hw);
5128
5129 return 0;
5130}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005131
Felipe Balbia390e852011-10-06 10:07:44 +03005132static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5133{
5134 struct wl1271 *wl = cookie;
5135 unsigned long flags;
5136
5137 wl1271_debug(DEBUG_IRQ, "IRQ");
5138
5139 /* complete the ELP completion */
5140 spin_lock_irqsave(&wl->wl_lock, flags);
5141 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5142 if (wl->elp_compl) {
5143 complete(wl->elp_compl);
5144 wl->elp_compl = NULL;
5145 }
5146
5147 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5148 /* don't enqueue a work right now. mark it as pending */
5149 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5150 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5151 disable_irq_nosync(wl->irq);
5152 pm_wakeup_event(wl->dev, 0);
5153 spin_unlock_irqrestore(&wl->wl_lock, flags);
5154 return IRQ_HANDLED;
5155 }
5156 spin_unlock_irqrestore(&wl->wl_lock, flags);
5157
5158 return IRQ_WAKE_THREAD;
5159}
5160
Felipe Balbice2a2172011-10-05 14:12:55 +03005161static int __devinit wl12xx_probe(struct platform_device *pdev)
5162{
Felipe Balbia390e852011-10-06 10:07:44 +03005163 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5164 struct ieee80211_hw *hw;
5165 struct wl1271 *wl;
5166 unsigned long irqflags;
5167 int ret = -ENODEV;
5168
5169 hw = wl1271_alloc_hw();
5170 if (IS_ERR(hw)) {
5171 wl1271_error("can't allocate hw");
5172 ret = PTR_ERR(hw);
5173 goto out;
5174 }
5175
5176 wl = hw->priv;
5177 wl->irq = platform_get_irq(pdev, 0);
5178 wl->ref_clock = pdata->board_ref_clock;
5179 wl->tcxo_clock = pdata->board_tcxo_clock;
5180 wl->platform_quirks = pdata->platform_quirks;
5181 wl->set_power = pdata->set_power;
5182 wl->dev = &pdev->dev;
5183 wl->if_ops = pdata->ops;
5184
5185 platform_set_drvdata(pdev, wl);
5186
5187 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5188 irqflags = IRQF_TRIGGER_RISING;
5189 else
5190 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5191
5192 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5193 irqflags,
5194 pdev->name, wl);
5195 if (ret < 0) {
5196 wl1271_error("request_irq() failed: %d", ret);
5197 goto out_free_hw;
5198 }
5199
5200 ret = enable_irq_wake(wl->irq);
5201 if (!ret) {
5202 wl->irq_wake_enabled = true;
5203 device_init_wakeup(wl->dev, 1);
5204 if (pdata->pwr_in_suspend)
5205 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5206
5207 }
5208 disable_irq(wl->irq);
5209
5210 ret = wl1271_init_ieee80211(wl);
5211 if (ret)
5212 goto out_irq;
5213
5214 ret = wl1271_register_hw(wl);
5215 if (ret)
5216 goto out_irq;
5217
Felipe Balbif79f8902011-10-06 13:05:25 +03005218 /* Create sysfs file to control bt coex state */
5219 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5220 if (ret < 0) {
5221 wl1271_error("failed to create sysfs file bt_coex_state");
5222 goto out_irq;
5223 }
5224
5225 /* Create sysfs file to get HW PG version */
5226 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5227 if (ret < 0) {
5228 wl1271_error("failed to create sysfs file hw_pg_ver");
5229 goto out_bt_coex_state;
5230 }
5231
5232 /* Create sysfs file for the FW log */
5233 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5234 if (ret < 0) {
5235 wl1271_error("failed to create sysfs file fwlog");
5236 goto out_hw_pg_ver;
5237 }
5238
Felipe Balbice2a2172011-10-05 14:12:55 +03005239 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005240
Felipe Balbif79f8902011-10-06 13:05:25 +03005241out_hw_pg_ver:
5242 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5243
5244out_bt_coex_state:
5245 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5246
Felipe Balbia390e852011-10-06 10:07:44 +03005247out_irq:
5248 free_irq(wl->irq, wl);
5249
5250out_free_hw:
5251 wl1271_free_hw(wl);
5252
5253out:
5254 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005255}
5256
5257static int __devexit wl12xx_remove(struct platform_device *pdev)
5258{
Felipe Balbia390e852011-10-06 10:07:44 +03005259 struct wl1271 *wl = platform_get_drvdata(pdev);
5260
5261 if (wl->irq_wake_enabled) {
5262 device_init_wakeup(wl->dev, 0);
5263 disable_irq_wake(wl->irq);
5264 }
5265 wl1271_unregister_hw(wl);
5266 free_irq(wl->irq, wl);
5267 wl1271_free_hw(wl);
5268
Felipe Balbice2a2172011-10-05 14:12:55 +03005269 return 0;
5270}
5271
5272static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005273 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005274 { } /* Terminating Entry */
5275};
5276MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5277
5278static struct platform_driver wl12xx_driver = {
5279 .probe = wl12xx_probe,
5280 .remove = __devexit_p(wl12xx_remove),
5281 .id_table = wl12xx_id_table,
5282 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005283 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005284 .owner = THIS_MODULE,
5285 }
5286};
5287
5288static int __init wl12xx_init(void)
5289{
5290 return platform_driver_register(&wl12xx_driver);
5291}
5292module_init(wl12xx_init);
5293
5294static void __exit wl12xx_exit(void)
5295{
5296 platform_driver_unregister(&wl12xx_driver);
5297}
5298module_exit(wl12xx_exit);
5299
Guy Eilam491bbd62011-01-12 10:33:29 +01005300u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005301EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005302module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005303MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5304
Ido Yariv95dac04f2011-06-06 14:57:06 +03005305module_param_named(fwlog, fwlog_param, charp, 0);
5306MODULE_PARM_DESC(keymap,
5307 "FW logger options: continuous, ondemand, dbgpins or disable");
5308
Eliad Peller2a5bff02011-08-25 18:10:59 +03005309module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5310MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5311
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005312MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005313MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005314MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");