blob: 2f7bfa86c8cd51e8256710ce10528119289acfcc [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Felipe Balbia390e852011-10-06 10:07:44 +030035#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "wl12xx.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030038#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030039#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000040#include "reg.h"
41#include "io.h"
42#include "event.h"
43#include "tx.h"
44#include "rx.h"
45#include "ps.h"
46#include "init.h"
47#include "debugfs.h"
48#include "cmd.h"
49#include "boot.h"
50#include "testmode.h"
51#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030052
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020053#define WL1271_BOOT_RETRIES 3
54
Juuso Oikarinen8a080482009-10-13 12:47:44 +030055static struct conf_drv_settings default_conf = {
56 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030057 .params = {
58 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
61 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
62 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
64 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
65 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
66 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
68 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
69 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
70 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
71 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
73 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
74 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
75 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
76 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
77 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
78 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
79 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
82 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
83 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
84 /* active scan params */
85 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
86 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
87 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
88 /* passive scan params */
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
91 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
92 /* passive scan in dual antenna params */
93 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
94 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
95 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
96 /* general params */
97 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
98 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
99 [CONF_SG_BEACON_MISS_PERCENT] = 60,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_RXT] = 1200,
102 [CONF_SG_TXT] = 1000,
103 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
104 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
105 [CONF_SG_HV3_MAX_SERVED] = 6,
106 [CONF_SG_PS_POLL_TIMEOUT] = 10,
107 [CONF_SG_UPSD_TIMEOUT] = 10,
108 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
109 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
110 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
111 /* AP params */
112 [CONF_AP_BEACON_MISS_TX] = 3,
113 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
114 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
115 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
116 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
117 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300118 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200119 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300120 },
121 .rx = {
122 .rx_msdu_life_time = 512000,
123 .packet_detection_threshold = 0,
124 .ps_poll_timeout = 15,
125 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300126 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200127 .rx_cca_threshold = 0,
128 .irq_blk_threshold = 0xFFFF,
129 .irq_pkt_threshold = 0,
130 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300131 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
132 },
133 .tx = {
134 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200135 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300136 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300137 .short_retry_limit = 10,
138 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200139 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300140 },
141 .ac_conf_count = 4,
142 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200143 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300144 .ac = CONF_TX_AC_BE,
145 .cw_min = 15,
146 .cw_max = 63,
147 .aifsn = 3,
148 .tx_op_limit = 0,
149 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200150 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300151 .ac = CONF_TX_AC_BK,
152 .cw_min = 15,
153 .cw_max = 63,
154 .aifsn = 7,
155 .tx_op_limit = 0,
156 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200157 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300158 .ac = CONF_TX_AC_VI,
159 .cw_min = 15,
160 .cw_max = 63,
161 .aifsn = CONF_TX_AIFS_PIFS,
162 .tx_op_limit = 3008,
163 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200164 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300165 .ac = CONF_TX_AC_VO,
166 .cw_min = 15,
167 .cw_max = 63,
168 .aifsn = CONF_TX_AIFS_PIFS,
169 .tx_op_limit = 1504,
170 },
171 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300172 .max_tx_retries = 100,
173 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300175 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200176 [CONF_TX_AC_BE] = {
177 .queue_id = CONF_TX_AC_BE,
178 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300179 .tsid = CONF_TX_AC_BE,
180 .ps_scheme = CONF_PS_SCHEME_LEGACY,
181 .ack_policy = CONF_ACK_POLICY_LEGACY,
182 .apsd_conf = {0, 0},
183 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200184 [CONF_TX_AC_BK] = {
185 .queue_id = CONF_TX_AC_BK,
186 .channel_type = CONF_CHANNEL_TYPE_EDCF,
187 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300188 .ps_scheme = CONF_PS_SCHEME_LEGACY,
189 .ack_policy = CONF_ACK_POLICY_LEGACY,
190 .apsd_conf = {0, 0},
191 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200192 [CONF_TX_AC_VI] = {
193 .queue_id = CONF_TX_AC_VI,
194 .channel_type = CONF_CHANNEL_TYPE_EDCF,
195 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .ps_scheme = CONF_PS_SCHEME_LEGACY,
197 .ack_policy = CONF_ACK_POLICY_LEGACY,
198 .apsd_conf = {0, 0},
199 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200200 [CONF_TX_AC_VO] = {
201 .queue_id = CONF_TX_AC_VO,
202 .channel_type = CONF_CHANNEL_TYPE_EDCF,
203 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300204 .ps_scheme = CONF_PS_SCHEME_LEGACY,
205 .ack_policy = CONF_ACK_POLICY_LEGACY,
206 .apsd_conf = {0, 0},
207 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300208 },
209 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200210 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300211 .tx_compl_threshold = 4,
212 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
213 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200214 .tmpl_short_retry_limit = 10,
215 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300216 },
217 .conn = {
218 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300219 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300221 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300222 .bcn_filt_ie = {
223 [0] = {
224 .ie = WLAN_EID_CHANNEL_SWITCH,
225 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300226 },
227 [1] = {
228 .ie = WLAN_EID_HT_INFORMATION,
229 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
230 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200232 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 .bss_lose_timeout = 100,
234 .beacon_rx_timeout = 10000,
235 .broadcast_timeout = 20000,
236 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300237 .ps_poll_threshold = 10,
238 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300239 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200240 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300241 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300242 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200243 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300244 .keep_alive_interval = 55000,
245 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300246 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200247 .itrim = {
248 .enable = false,
249 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200250 },
251 .pm_config = {
252 .host_clk_settling_time = 5000,
253 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 },
255 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300256 .trigger_pacing = 1,
257 .avg_weight_rssi_beacon = 20,
258 .avg_weight_rssi_data = 10,
259 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100260 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200261 },
262 .scan = {
263 .min_dwell_time_active = 7500,
264 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100265 .min_dwell_time_passive = 100000,
266 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200267 .num_probe_reqs = 2,
268 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300269 .sched_scan = {
270 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300271 .min_dwell_time_active = 30,
272 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300274 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300275 .num_probe_reqs = 2,
276 .rssi_threshold = -90,
277 .snr_threshold = 0,
278 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200279 .rf = {
280 .tx_per_channel_power_compensation_2 = {
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 },
283 .tx_per_channel_power_compensation_5 = {
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 },
288 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300290 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100291 .tx_ba_win_size = 64,
292 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300293 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100294 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200295 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200296 .num_stations = 1,
297 .ssid_profiles = 1,
298 .rx_block_num = 70,
299 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300300 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200301 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200302 .min_req_rx_blocks = 22,
303 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200304 },
305 .mem_wl128x = {
306 .num_stations = 1,
307 .ssid_profiles = 1,
308 .rx_block_num = 40,
309 .tx_min_block_num = 40,
310 .dynamic_memory = 1,
311 .min_req_tx_blocks = 45,
312 .min_req_rx_blocks = 22,
313 .tx_min = 27,
314 },
Shahar Leviff868432011-04-11 15:41:46 +0300315 .fm_coex = {
316 .enable = true,
317 .swallow_period = 5,
318 .n_divider_fref_set_1 = 0xff, /* default */
319 .n_divider_fref_set_2 = 12,
320 .m_divider_fref_set_1 = 148,
321 .m_divider_fref_set_2 = 0xffff, /* default */
322 .coex_pll_stabilization_time = 0xffffffff, /* default */
323 .ldo_stabilization_time = 0xffff, /* default */
324 .fm_disturbed_band_margin = 0xff, /* default */
325 .swallow_clk_diff = 0xff, /* default */
326 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300327 .rx_streaming = {
328 .duration = 150,
329 .queues = 0x1,
330 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300331 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300332 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300333 .fwlog = {
334 .mode = WL12XX_FWLOG_ON_DEMAND,
335 .mem_blocks = 2,
336 .severity = 0,
337 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
338 .output = WL12XX_FWLOG_OUTPUT_HOST,
339 .threshold = 0,
340 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300341 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300342 .rate = {
343 .rate_retry_score = 32000,
344 .per_add = 8192,
345 .per_th1 = 2048,
346 .per_th2 = 4096,
347 .max_per = 8100,
348 .inverse_curiosity_factor = 5,
349 .tx_fail_low_th = 4,
350 .tx_fail_high_th = 10,
351 .per_alpha_shift = 4,
352 .per_add_shift = 13,
353 .per_beta1_shift = 10,
354 .per_beta2_shift = 8,
355 .rate_check_up = 2,
356 .rate_check_down = 12,
357 .rate_retry_policy = {
358 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00,
361 },
362 },
Eliad Peller94877752011-08-28 15:11:56 +0300363 .hangover = {
364 .recover_time = 0,
365 .hangover_period = 20,
366 .dynamic_mode = 1,
367 .early_termination_mode = 1,
368 .max_period = 20,
369 .min_period = 1,
370 .increase_delta = 1,
371 .decrease_delta = 2,
372 .quiet_time = 4,
373 .increase_time = 1,
374 .window_size = 16,
375 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300376};
377
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300379static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300380
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300381static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200382 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300383 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200384static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200385static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200386
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200387static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300388static LIST_HEAD(wl_list);
389
Eliad Pellerba8447f2011-10-10 10:13:00 +0200390static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
391 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300392{
393 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200394
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300395 if (operstate != IF_OPER_UP)
396 return 0;
397
Eliad Peller8181aec2011-10-10 10:13:04 +0200398 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300399 return 0;
400
Eliad Peller154da672011-10-05 11:55:53 +0200401 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300402 if (ret < 0)
403 return ret;
404
Eliad Peller0603d892011-10-05 11:55:51 +0200405 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300406
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300407 wl1271_info("Association completed.");
408 return 0;
409}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300410static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
411 void *arg)
412{
413 struct net_device *dev = arg;
414 struct wireless_dev *wdev;
415 struct wiphy *wiphy;
416 struct ieee80211_hw *hw;
417 struct wl1271 *wl;
418 struct wl1271 *wl_temp;
Eliad Pellerba8447f2011-10-10 10:13:00 +0200419 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300420 int ret = 0;
421
422 /* Check that this notification is for us. */
423 if (what != NETDEV_CHANGE)
424 return NOTIFY_DONE;
425
426 wdev = dev->ieee80211_ptr;
427 if (wdev == NULL)
428 return NOTIFY_DONE;
429
430 wiphy = wdev->wiphy;
431 if (wiphy == NULL)
432 return NOTIFY_DONE;
433
434 hw = wiphy_priv(wiphy);
435 if (hw == NULL)
436 return NOTIFY_DONE;
437
438 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200439 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300440 list_for_each_entry(wl, &wl_list, list) {
441 if (wl == wl_temp)
442 break;
443 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200444 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300445 if (wl != wl_temp)
446 return NOTIFY_DONE;
447
448 mutex_lock(&wl->mutex);
449
450 if (wl->state == WL1271_STATE_OFF)
451 goto out;
452
Eliad Pellerba8447f2011-10-10 10:13:00 +0200453 wl12xx_for_each_wlvif_sta(wl, wlvif) {
454 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
455 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300456
Eliad Pellerba8447f2011-10-10 10:13:00 +0200457 ret = wl1271_ps_elp_wakeup(wl);
458 if (ret < 0)
459 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300460
Eliad Pellerba8447f2011-10-10 10:13:00 +0200461 wl1271_check_operstate(wl, wlvif, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300462
Eliad Pellerba8447f2011-10-10 10:13:00 +0200463 wl1271_ps_elp_sleep(wl);
464 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300465out:
466 mutex_unlock(&wl->mutex);
467
468 return NOTIFY_OK;
469}
470
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100471static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200472 struct regulatory_request *request)
473{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100474 struct ieee80211_supported_band *band;
475 struct ieee80211_channel *ch;
476 int i;
477
478 band = wiphy->bands[IEEE80211_BAND_5GHZ];
479 for (i = 0; i < band->n_channels; i++) {
480 ch = &band->channels[i];
481 if (ch->flags & IEEE80211_CHAN_DISABLED)
482 continue;
483
484 if (ch->flags & IEEE80211_CHAN_RADAR)
485 ch->flags |= IEEE80211_CHAN_NO_IBSS |
486 IEEE80211_CHAN_PASSIVE_SCAN;
487
488 }
489
490 return 0;
491}
492
Eliad Peller9eb599e2011-10-10 10:12:59 +0200493static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
494 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300495{
496 int ret = 0;
497
498 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200499 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300500 if (ret < 0)
501 goto out;
502
503 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200504 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300505 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200506 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300507out:
508 return ret;
509}
510
511/*
512 * this function is being called when the rx_streaming interval
513 * has beed changed or rx_streaming should be disabled
514 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200515int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300516{
517 int ret = 0;
518 int period = wl->conf.rx_streaming.interval;
519
520 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200521 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300522 goto out;
523
524 /* reconfigure/disable according to new streaming_period */
525 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200526 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300527 (wl->conf.rx_streaming.always ||
528 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200529 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300530 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200531 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300532 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200533 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300534 }
535out:
536 return ret;
537}
538
539static void wl1271_rx_streaming_enable_work(struct work_struct *work)
540{
541 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200542 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
543 rx_streaming_enable_work);
544 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300545
546 mutex_lock(&wl->mutex);
547
Eliad Peller0744bdb2011-10-10 10:13:05 +0200548 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200549 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300550 (!wl->conf.rx_streaming.always &&
551 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
552 goto out;
553
554 if (!wl->conf.rx_streaming.interval)
555 goto out;
556
557 ret = wl1271_ps_elp_wakeup(wl);
558 if (ret < 0)
559 goto out;
560
Eliad Peller9eb599e2011-10-10 10:12:59 +0200561 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300562 if (ret < 0)
563 goto out_sleep;
564
565 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200566 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300567 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
568
569out_sleep:
570 wl1271_ps_elp_sleep(wl);
571out:
572 mutex_unlock(&wl->mutex);
573}
574
575static void wl1271_rx_streaming_disable_work(struct work_struct *work)
576{
577 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200578 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
579 rx_streaming_disable_work);
580 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300581
582 mutex_lock(&wl->mutex);
583
Eliad Peller0744bdb2011-10-10 10:13:05 +0200584 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300585 goto out;
586
587 ret = wl1271_ps_elp_wakeup(wl);
588 if (ret < 0)
589 goto out;
590
Eliad Peller9eb599e2011-10-10 10:12:59 +0200591 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300592 if (ret)
593 goto out_sleep;
594
595out_sleep:
596 wl1271_ps_elp_sleep(wl);
597out:
598 mutex_unlock(&wl->mutex);
599}
600
601static void wl1271_rx_streaming_timer(unsigned long data)
602{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200603 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
604 struct wl1271 *wl = wlvif->wl;
605 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300606}
607
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300608static void wl1271_conf_init(struct wl1271 *wl)
609{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300610
611 /*
612 * This function applies the default configuration to the driver. This
613 * function is invoked upon driver load (spi probe.)
614 *
615 * The configuration is stored in a run-time structure in order to
616 * facilitate for run-time adjustment of any of the parameters. Making
617 * changes to the configuration structure will apply the new values on
618 * the next interface up (wl1271_op_start.)
619 */
620
621 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300622 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300623
Ido Yariv95dac04f2011-06-06 14:57:06 +0300624 /* Adjust settings according to optional module parameters */
625 if (fwlog_param) {
626 if (!strcmp(fwlog_param, "continuous")) {
627 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
628 } else if (!strcmp(fwlog_param, "ondemand")) {
629 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
630 } else if (!strcmp(fwlog_param, "dbgpins")) {
631 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
632 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
633 } else if (!strcmp(fwlog_param, "disable")) {
634 wl->conf.fwlog.mem_blocks = 0;
635 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
636 } else {
637 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
638 }
639 }
640}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300641
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300642static int wl1271_plt_init(struct wl1271 *wl)
643{
Eliad Peller188e7f52011-12-06 12:15:06 +0200644 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300645
Shahar Levi49d750ca2011-03-06 16:32:09 +0200646 if (wl->chip.id == CHIP_ID_1283_PG20)
647 ret = wl128x_cmd_general_parms(wl);
648 else
649 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200650 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200651 return ret;
652
Shahar Levi49d750ca2011-03-06 16:32:09 +0200653 if (wl->chip.id == CHIP_ID_1283_PG20)
654 ret = wl128x_cmd_radio_parms(wl);
655 else
656 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200657 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200658 return ret;
659
Shahar Levi49d750ca2011-03-06 16:32:09 +0200660 if (wl->chip.id != CHIP_ID_1283_PG20) {
661 ret = wl1271_cmd_ext_radio_parms(wl);
662 if (ret < 0)
663 return ret;
664 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200665 if (ret < 0)
666 return ret;
667
Shahar Levi48a61472011-03-06 16:32:08 +0200668 /* Chip-specific initializations */
669 ret = wl1271_chip_specific_init(wl);
670 if (ret < 0)
671 return ret;
672
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300673 ret = wl1271_acx_init_mem_config(wl);
674 if (ret < 0)
675 return ret;
676
Luciano Coelho12419cc2010-02-18 13:25:44 +0200677 /* PHY layer config */
678 ret = wl1271_init_phy_config(wl);
679 if (ret < 0)
680 goto out_free_memmap;
681
Eliad Peller7f0979882011-08-14 13:17:06 +0300682 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600683 if (ret < 0)
684 goto out_free_memmap;
685
Luciano Coelho12419cc2010-02-18 13:25:44 +0200686 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200687 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300688 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200689 goto out_free_memmap;
690
691 /* Configure for CAM power saving (ie. always active) */
692 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
693 if (ret < 0)
694 goto out_free_memmap;
695
696 /* configure PM */
697 ret = wl1271_acx_pm_config(wl);
698 if (ret < 0)
699 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300700
701 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200702
703 out_free_memmap:
704 kfree(wl->target_mem_map);
705 wl->target_mem_map = NULL;
706
707 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300708}
709
Eliad Peller6e8cd332011-10-10 10:13:13 +0200710static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
711 struct wl12xx_vif *wlvif,
712 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200713{
Arik Nemtsovda032092011-08-25 12:43:15 +0300714 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200715
Arik Nemtsovb622d992011-02-23 00:22:31 +0200716 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300717 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200718
719 /*
720 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300721 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200722 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300723 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200724 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200725
Arik Nemtsovda032092011-08-25 12:43:15 +0300726 /*
727 * Start high-level PS if the STA is asleep with enough blocks in FW.
728 * Make an exception if this is the only connected station. In this
729 * case FW-memory congestion is not a problem.
730 */
731 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200732 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200733}
734
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300735static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200736 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300737 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200738{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200739 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200740 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300741 u8 hlid, cnt;
742
743 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200744
745 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
746 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
747 wl1271_debug(DEBUG_PSM,
748 "link ps prev 0x%x cur 0x%x changed 0x%x",
749 wl->ap_fw_ps_map, cur_fw_ps_map,
750 wl->ap_fw_ps_map ^ cur_fw_ps_map);
751
752 wl->ap_fw_ps_map = cur_fw_ps_map;
753 }
754
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200755 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
756 lnk = &wl->links[hlid];
757 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200758
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200759 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
760 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200761
Eliad Peller6e8cd332011-10-10 10:13:13 +0200762 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
763 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200764 }
765}
766
Eliad Peller4d56ad92011-08-14 13:17:05 +0300767static void wl12xx_fw_status(struct wl1271 *wl,
768 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300769{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200770 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200771 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200772 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300773 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300774 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300775
Eliad Peller4d56ad92011-08-14 13:17:05 +0300776 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200777
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300778 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
779 "drv_rx_counter = %d, tx_results_counter = %d)",
780 status->intr,
781 status->fw_rx_counter,
782 status->drv_rx_counter,
783 status->tx_results_counter);
784
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300785 for (i = 0; i < NUM_TX_QUEUES; i++) {
786 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300787 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300788 (status->tx_released_pkts[i] -
789 wl->tx_pkts_freed[i]) & 0xff;
790
791 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
792 }
793
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300794 /* prevent wrap-around in total blocks counter */
795 if (likely(wl->tx_blocks_freed <=
796 le32_to_cpu(status->total_released_blks)))
797 freed_blocks = le32_to_cpu(status->total_released_blks) -
798 wl->tx_blocks_freed;
799 else
800 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
801 le32_to_cpu(status->total_released_blks);
802
Eliad Peller4d56ad92011-08-14 13:17:05 +0300803 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200804
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300805 wl->tx_allocated_blocks -= freed_blocks;
806
Eliad Peller4d56ad92011-08-14 13:17:05 +0300807 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200808
Eliad Peller4d56ad92011-08-14 13:17:05 +0300809 /*
810 * The FW might change the total number of TX memblocks before
811 * we get a notification about blocks being released. Thus, the
812 * available blocks calculation might yield a temporary result
813 * which is lower than the actual available blocks. Keeping in
814 * mind that only blocks that were allocated can be moved from
815 * TX to RX, tx_blocks_available should never decrease here.
816 */
817 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
818 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300819
Ido Yariva5225502010-10-12 14:49:10 +0200820 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200821 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200822 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300823
Eliad Peller4d56ad92011-08-14 13:17:05 +0300824 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200825 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200826 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200827 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300828
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300829 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200830 getnstimeofday(&ts);
831 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
832 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300833}
834
Ido Yariva6208652011-03-01 15:14:41 +0200835static void wl1271_flush_deferred_work(struct wl1271 *wl)
836{
837 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200838
Ido Yariva6208652011-03-01 15:14:41 +0200839 /* Pass all received frames to the network stack */
840 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
841 ieee80211_rx_ni(wl->hw, skb);
842
843 /* Return sent skbs to the network stack */
844 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300845 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200846}
847
848static void wl1271_netstack_work(struct work_struct *work)
849{
850 struct wl1271 *wl =
851 container_of(work, struct wl1271, netstack_work);
852
853 do {
854 wl1271_flush_deferred_work(wl);
855 } while (skb_queue_len(&wl->deferred_rx_queue));
856}
857
858#define WL1271_IRQ_MAX_LOOPS 256
859
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300860static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300861{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300862 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300863 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200864 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200865 struct wl1271 *wl = (struct wl1271 *)cookie;
866 bool done = false;
867 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200868 unsigned long flags;
869
870 /* TX might be handled here, avoid redundant work */
871 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
872 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300873
Ido Yariv341b7cd2011-03-31 10:07:01 +0200874 /*
875 * In case edge triggered interrupt must be used, we cannot iterate
876 * more than once without introducing race conditions with the hardirq.
877 */
878 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
879 loopcount = 1;
880
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300881 mutex_lock(&wl->mutex);
882
883 wl1271_debug(DEBUG_IRQ, "IRQ work");
884
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200885 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300886 goto out;
887
Ido Yariva6208652011-03-01 15:14:41 +0200888 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300889 if (ret < 0)
890 goto out;
891
Ido Yariva6208652011-03-01 15:14:41 +0200892 while (!done && loopcount--) {
893 /*
894 * In order to avoid a race with the hardirq, clear the flag
895 * before acknowledging the chip. Since the mutex is held,
896 * wl1271_ps_elp_wakeup cannot be called concurrently.
897 */
898 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
899 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200900
Eliad Peller4d56ad92011-08-14 13:17:05 +0300901 wl12xx_fw_status(wl, wl->fw_status);
902 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200903 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200904 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200905 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200906 continue;
907 }
908
Eliad Pellerccc83b02010-10-27 14:09:57 +0200909 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
910 wl1271_error("watchdog interrupt received! "
911 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300912 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200913
914 /* restarting the chip. ignore any other interrupt. */
915 goto out;
916 }
917
Ido Yariva6208652011-03-01 15:14:41 +0200918 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200919 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
920
Eliad Peller4d56ad92011-08-14 13:17:05 +0300921 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200922
Ido Yariva5225502010-10-12 14:49:10 +0200923 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200924 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200925 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300926 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200927 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200928 /*
929 * In order to avoid starvation of the TX path,
930 * call the work function directly.
931 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200932 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200933 } else {
934 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200935 }
936
Ido Yariv8aad2462011-03-01 15:14:38 +0200937 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300938 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200939 (wl->tx_results_count & 0xff))
940 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200941
942 /* Make sure the deferred queues don't get too long */
943 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
944 skb_queue_len(&wl->deferred_rx_queue);
945 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
946 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200947 }
948
949 if (intr & WL1271_ACX_INTR_EVENT_A) {
950 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
951 wl1271_event_handle(wl, 0);
952 }
953
954 if (intr & WL1271_ACX_INTR_EVENT_B) {
955 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
956 wl1271_event_handle(wl, 1);
957 }
958
959 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
960 wl1271_debug(DEBUG_IRQ,
961 "WL1271_ACX_INTR_INIT_COMPLETE");
962
963 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
964 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300965 }
966
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300967 wl1271_ps_elp_sleep(wl);
968
969out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200970 spin_lock_irqsave(&wl->wl_lock, flags);
971 /* In case TX was not handled here, queue TX work */
972 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
973 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300974 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200975 ieee80211_queue_work(wl->hw, &wl->tx_work);
976 spin_unlock_irqrestore(&wl->wl_lock, flags);
977
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300978 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200979
980 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300981}
982
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983static int wl1271_fetch_firmware(struct wl1271 *wl)
984{
985 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200986 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300987 int ret;
988
Arik Nemtsovc302b2c2011-08-17 10:45:48 +0300989 if (wl->chip.id == CHIP_ID_1283_PG20)
990 fw_name = WL128X_FW_NAME;
991 else
992 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200993
994 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
995
Felipe Balbia390e852011-10-06 10:07:44 +0300996 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300997
998 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +0100999 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000 return ret;
1001 }
1002
1003 if (fw->size % 4) {
1004 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1005 fw->size);
1006 ret = -EILSEQ;
1007 goto out;
1008 }
1009
Arik Nemtsov166d5042010-10-16 21:44:57 +02001010 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001012 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001013
1014 if (!wl->fw) {
1015 wl1271_error("could not allocate memory for the firmware");
1016 ret = -ENOMEM;
1017 goto out;
1018 }
1019
1020 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021 ret = 0;
1022
1023out:
1024 release_firmware(fw);
1025
1026 return ret;
1027}
1028
1029static int wl1271_fetch_nvs(struct wl1271 *wl)
1030{
1031 const struct firmware *fw;
1032 int ret;
1033
Felipe Balbia390e852011-10-06 10:07:44 +03001034 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035
1036 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001037 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
1038 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039 return ret;
1040 }
1041
Shahar Levibc765bf2011-03-06 16:32:10 +02001042 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043
1044 if (!wl->nvs) {
1045 wl1271_error("could not allocate memory for the nvs file");
1046 ret = -ENOMEM;
1047 goto out;
1048 }
1049
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001050 wl->nvs_len = fw->size;
1051
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052out:
1053 release_firmware(fw);
1054
1055 return ret;
1056}
1057
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001058void wl12xx_queue_recovery_work(struct wl1271 *wl)
1059{
1060 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1061 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1062}
1063
Ido Yariv95dac04f2011-06-06 14:57:06 +03001064size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1065{
1066 size_t len = 0;
1067
1068 /* The FW log is a length-value list, find where the log end */
1069 while (len < maxlen) {
1070 if (memblock[len] == 0)
1071 break;
1072 if (len + memblock[len] + 1 > maxlen)
1073 break;
1074 len += memblock[len] + 1;
1075 }
1076
1077 /* Make sure we have enough room */
1078 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1079
1080 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1081 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1082 wl->fwlog_size += len;
1083
1084 return len;
1085}
1086
1087static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1088{
1089 u32 addr;
1090 u32 first_addr;
1091 u8 *block;
1092
1093 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1094 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1095 (wl->conf.fwlog.mem_blocks == 0))
1096 return;
1097
1098 wl1271_info("Reading FW panic log");
1099
1100 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1101 if (!block)
1102 return;
1103
1104 /*
1105 * Make sure the chip is awake and the logger isn't active.
1106 * This might fail if the firmware hanged.
1107 */
1108 if (!wl1271_ps_elp_wakeup(wl))
1109 wl12xx_cmd_stop_fwlog(wl);
1110
1111 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001112 wl12xx_fw_status(wl, wl->fw_status);
1113 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001114 if (!first_addr)
1115 goto out;
1116
1117 /* Traverse the memory blocks linked list */
1118 addr = first_addr;
1119 do {
1120 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1121 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1122 false);
1123
1124 /*
1125 * Memory blocks are linked to one another. The first 4 bytes
1126 * of each memory block hold the hardware address of the next
1127 * one. The last memory block points to the first one.
1128 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001129 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001130 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1131 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1132 break;
1133 } while (addr && (addr != first_addr));
1134
1135 wake_up_interruptible(&wl->fwlog_waitq);
1136
1137out:
1138 kfree(block);
1139}
1140
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001141static void wl1271_recovery_work(struct work_struct *work)
1142{
1143 struct wl1271 *wl =
1144 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001145 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001146 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001147
1148 mutex_lock(&wl->mutex);
1149
1150 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001151 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001152
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001153 /* Avoid a recursive recovery */
1154 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1155
Ido Yariv95dac04f2011-06-06 14:57:06 +03001156 wl12xx_read_fwlog_panic(wl);
1157
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001158 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1159 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001160
Eliad Peller2a5bff02011-08-25 18:10:59 +03001161 BUG_ON(bug_on_recovery);
1162
Oz Krakowskib992c682011-06-26 10:36:02 +03001163 /*
1164 * Advance security sequence number to overcome potential progress
1165 * in the firmware during recovery. This doens't hurt if the network is
1166 * not encrypted.
1167 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001168 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001169 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001170 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001171 wlvif->tx_security_seq +=
1172 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1173 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001174
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001175 /* Prevent spurious TX during FW restart */
1176 ieee80211_stop_queues(wl->hw);
1177
Luciano Coelho33c2c062011-05-10 14:46:02 +03001178 if (wl->sched_scanning) {
1179 ieee80211_sched_scan_stopped(wl->hw);
1180 wl->sched_scanning = false;
1181 }
1182
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001183 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001184 while (!list_empty(&wl->wlvif_list)) {
1185 wlvif = list_first_entry(&wl->wlvif_list,
1186 struct wl12xx_vif, list);
1187 vif = wl12xx_wlvif_to_vif(wlvif);
1188 __wl1271_op_remove_interface(wl, vif, false);
1189 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001190 mutex_unlock(&wl->mutex);
1191 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001192
1193 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1194
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001195 ieee80211_restart_hw(wl->hw);
1196
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001197 /*
1198 * Its safe to enable TX now - the queues are stopped after a request
1199 * to restart the HW.
1200 */
1201 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001202 return;
1203out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001204 mutex_unlock(&wl->mutex);
1205}
1206
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001207static void wl1271_fw_wakeup(struct wl1271 *wl)
1208{
1209 u32 elp_reg;
1210
1211 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001212 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001213}
1214
1215static int wl1271_setup(struct wl1271 *wl)
1216{
1217 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1218 if (!wl->fw_status)
1219 return -ENOMEM;
1220
1221 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1222 if (!wl->tx_res_if) {
1223 kfree(wl->fw_status);
1224 return -ENOMEM;
1225 }
1226
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001227 return 0;
1228}
1229
1230static int wl1271_chip_wakeup(struct wl1271 *wl)
1231{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001232 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001233 int ret = 0;
1234
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001235 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001236 ret = wl1271_power_on(wl);
1237 if (ret < 0)
1238 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001239 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001240 wl1271_io_reset(wl);
1241 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001242
1243 /* We don't need a real memory partition here, because we only want
1244 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001245 memset(&partition, 0, sizeof(partition));
1246 partition.reg.start = REGISTERS_BASE;
1247 partition.reg.size = REGISTERS_DOWN_SIZE;
1248 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001249
1250 /* ELP module wake up */
1251 wl1271_fw_wakeup(wl);
1252
1253 /* whal_FwCtrl_BootSm() */
1254
1255 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001256 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001257
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001258 /*
1259 * For wl127x based devices we could use the default block
1260 * size (512 bytes), but due to a bug in the sdio driver, we
1261 * need to set it explicitly after the chip is powered on. To
1262 * simplify the code and since the performance impact is
1263 * negligible, we use the same block size for all different
1264 * chip types.
1265 */
1266 if (!wl1271_set_block_size(wl))
1267 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001268
1269 switch (wl->chip.id) {
1270 case CHIP_ID_1271_PG10:
1271 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1272 wl->chip.id);
1273
1274 ret = wl1271_setup(wl);
1275 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001276 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001277 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001278 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001279
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001280 case CHIP_ID_1271_PG20:
1281 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1282 wl->chip.id);
1283
1284 ret = wl1271_setup(wl);
1285 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001286 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001287 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001288 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001289
Shahar Levi0830cee2011-03-06 16:32:20 +02001290 case CHIP_ID_1283_PG20:
1291 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1292 wl->chip.id);
1293
1294 ret = wl1271_setup(wl);
1295 if (ret < 0)
1296 goto out;
1297 break;
1298 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001299 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001300 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001302 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001303 }
1304
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001305 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306 ret = wl1271_fetch_firmware(wl);
1307 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001308 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001309 }
1310
1311 /* No NVS from netlink, try to get it from the filesystem */
1312 if (wl->nvs == NULL) {
1313 ret = wl1271_fetch_nvs(wl);
1314 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001315 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001316 }
1317
1318out:
1319 return ret;
1320}
1321
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322int wl1271_plt_start(struct wl1271 *wl)
1323{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001324 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001325 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001326 int ret;
1327
1328 mutex_lock(&wl->mutex);
1329
1330 wl1271_notice("power up");
1331
1332 if (wl->state != WL1271_STATE_OFF) {
1333 wl1271_error("cannot go into PLT state because not "
1334 "in off state: %d", wl->state);
1335 ret = -EBUSY;
1336 goto out;
1337 }
1338
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001339 while (retries) {
1340 retries--;
1341 ret = wl1271_chip_wakeup(wl);
1342 if (ret < 0)
1343 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001344
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001345 ret = wl1271_boot(wl);
1346 if (ret < 0)
1347 goto power_off;
1348
1349 ret = wl1271_plt_init(wl);
1350 if (ret < 0)
1351 goto irq_disable;
1352
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001353 wl->state = WL1271_STATE_PLT;
1354 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001355 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001356
Gery Kahn6f07b722011-07-18 14:21:49 +03001357 /* update hw/fw version info in wiphy struct */
1358 wiphy->hw_version = wl->chip.id;
1359 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1360 sizeof(wiphy->fw_version));
1361
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362 goto out;
1363
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001364irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001365 mutex_unlock(&wl->mutex);
1366 /* Unlocking the mutex in the middle of handling is
1367 inherently unsafe. In this case we deem it safe to do,
1368 because we need to let any possibly pending IRQ out of
1369 the system (and while we are WL1271_STATE_OFF the IRQ
1370 work function will not do anything.) Also, any other
1371 possible concurrent operations will fail due to the
1372 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001373 wl1271_disable_interrupts(wl);
1374 wl1271_flush_deferred_work(wl);
1375 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001376 mutex_lock(&wl->mutex);
1377power_off:
1378 wl1271_power_off(wl);
1379 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001380
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001381 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1382 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001383out:
1384 mutex_unlock(&wl->mutex);
1385
1386 return ret;
1387}
1388
Luciano Coelho4623ec72011-03-21 19:26:41 +02001389static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001390{
1391 int ret = 0;
1392
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001393 wl1271_notice("power down");
1394
1395 if (wl->state != WL1271_STATE_PLT) {
1396 wl1271_error("cannot power down because not in PLT "
1397 "state: %d", wl->state);
1398 ret = -EBUSY;
1399 goto out;
1400 }
1401
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402 wl1271_power_off(wl);
1403
1404 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001405 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001406
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001408 wl1271_disable_interrupts(wl);
1409 wl1271_flush_deferred_work(wl);
1410 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001411 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001412 mutex_lock(&wl->mutex);
1413out:
1414 return ret;
1415}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001416
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001417int wl1271_plt_stop(struct wl1271 *wl)
1418{
1419 int ret;
1420
1421 mutex_lock(&wl->mutex);
1422 ret = __wl1271_plt_stop(wl);
1423 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001424 return ret;
1425}
1426
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);
1451 dev_kfree_skb(skb);
1452 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));
1588 if (ret <= 0) {
1589 wl1271_warning("couldn't enter ps mode!");
1590 ret = -EBUSY;
1591 goto out;
1592 }
1593
1594 /* take mutex again, and wakeup */
1595 mutex_lock(&wl->mutex);
1596
1597 ret = wl1271_ps_elp_wakeup(wl);
1598 if (ret < 0)
1599 goto out_unlock;
1600 }
1601out_sleep:
1602 wl1271_ps_elp_sleep(wl);
1603out_unlock:
1604 mutex_unlock(&wl->mutex);
1605out:
1606 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
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002044static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2045 struct ieee80211_vif *vif)
2046{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002047 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002048 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002049 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002050 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002051 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002053 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002054 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002055
2056 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002057 ret = wl1271_ps_elp_wakeup(wl);
2058 if (ret < 0)
2059 goto out_unlock;
2060
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002061 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002062 wl1271_debug(DEBUG_MAC80211,
2063 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002064 ret = -EBUSY;
2065 goto out;
2066 }
2067
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002068 /*
2069 * in some very corner case HW recovery scenarios its possible to
2070 * get here before __wl1271_op_remove_interface is complete, so
2071 * opt out if that is the case.
2072 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002073 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2074 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002075 ret = -EBUSY;
2076 goto out;
2077 }
2078
Eliad Peller83587502011-10-10 10:12:53 +02002079 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002080 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002081 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002082
Eliad Peller252efa42011-10-05 11:56:00 +02002083 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002084 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002085 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2086 ret = -EINVAL;
2087 goto out;
2088 }
Eliad Peller1d095472011-10-10 10:12:49 +02002089
Eliad Peller784f6942011-10-05 11:55:39 +02002090 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002091 * TODO: after the nvs issue will be solved, move this block
2092 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002093 */
Eliad Peller1d095472011-10-10 10:12:49 +02002094 if (wl->state == WL1271_STATE_OFF) {
2095 /*
2096 * we still need this in order to configure the fw
2097 * while uploading the nvs
2098 */
2099 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002100
Eliad Peller1d095472011-10-10 10:12:49 +02002101 booted = wl12xx_init_fw(wl);
2102 if (!booted) {
2103 ret = -EINVAL;
2104 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002105 }
Eliad Peller1d095472011-10-10 10:12:49 +02002106 }
Eliad Peller04e80792011-08-14 13:17:09 +03002107
Eliad Peller1d095472011-10-10 10:12:49 +02002108 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2109 wlvif->bss_type == BSS_TYPE_IBSS) {
2110 /*
2111 * The device role is a special role used for
2112 * rx and tx frames prior to association (as
2113 * the STA role can get packets only from
2114 * its associated bssid)
2115 */
Eliad Peller784f6942011-10-05 11:55:39 +02002116 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002117 WL1271_ROLE_DEVICE,
2118 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002119 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002120 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002121 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002122
Eliad Peller1d095472011-10-10 10:12:49 +02002123 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2124 role_type, &wlvif->role_id);
2125 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002126 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002127
2128 ret = wl1271_init_vif_specific(wl, vif);
2129 if (ret < 0)
2130 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002131
2132 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002133 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002134 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002135
2136 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2137 wl->ap_count++;
2138 else
2139 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002140out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002141 wl1271_ps_elp_sleep(wl);
2142out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002143 mutex_unlock(&wl->mutex);
2144
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002145 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002146 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002147 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002148 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002149
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002150 return ret;
2151}
2152
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002153static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002154 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002155 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002156{
Eliad Peller536129c2011-10-05 11:55:45 +02002157 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002158 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002159
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002160 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002161
Eliad Peller10c8cd02011-10-10 10:13:06 +02002162 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2163 return;
2164
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002165 wl->vif = NULL;
2166
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002167 /* because of hardware recovery, we may get here twice */
2168 if (wl->state != WL1271_STATE_ON)
2169 return;
2170
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002171 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002172
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002173 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002174 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002175 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002176
Eliad Pellerbaf62772011-10-10 10:12:52 +02002177 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2178 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002179 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002180 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002181 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002182 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002183 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002184 }
2185
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002186 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2187 /* disable active roles */
2188 ret = wl1271_ps_elp_wakeup(wl);
2189 if (ret < 0)
2190 goto deinit;
2191
Eliad Peller536129c2011-10-05 11:55:45 +02002192 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002193 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002194 if (ret < 0)
2195 goto deinit;
2196 }
2197
Eliad Peller0603d892011-10-05 11:55:51 +02002198 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002199 if (ret < 0)
2200 goto deinit;
2201
2202 wl1271_ps_elp_sleep(wl);
2203 }
2204deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002205 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002206 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002207
2208 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2209 wlvif->bss_type == BSS_TYPE_IBSS) {
2210 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2211 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2212 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2213 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2214 } else {
2215 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2216 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2217 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2218 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2219 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2220 wl12xx_free_rate_policy(wl,
2221 &wlvif->ap.ucast_rate_idx[i]);
2222 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002223
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002224 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002225 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002226 if (wl->last_wlvif == wlvif)
2227 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002228 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002229 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002230 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002231 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002232
Eliad Pellera4e41302011-10-11 11:49:15 +02002233 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2234 wl->ap_count--;
2235 else
2236 wl->sta_count--;
2237
Eliad Pellerbaf62772011-10-10 10:12:52 +02002238 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002239 del_timer_sync(&wlvif->rx_streaming_timer);
2240 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2241 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002242 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002243
Eliad Pellerbaf62772011-10-10 10:12:52 +02002244 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002245}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002246
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002247static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2248 struct ieee80211_vif *vif)
2249{
2250 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002251 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002252 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002253
2254 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002255
2256 if (wl->state == WL1271_STATE_OFF ||
2257 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2258 goto out;
2259
Juuso Oikarinen67353292010-11-18 15:19:02 +02002260 /*
2261 * wl->vif can be null here if someone shuts down the interface
2262 * just when hardware recovery has been started.
2263 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002264 wl12xx_for_each_wlvif(wl, iter) {
2265 if (iter != wlvif)
2266 continue;
2267
Eliad Peller536129c2011-10-05 11:55:45 +02002268 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002269 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002270 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002271 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002272out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002273 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002274 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002275}
2276
Eliad Peller87fbcb02011-10-05 11:55:41 +02002277static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2278 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002279{
2280 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002281 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002282
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002283 /*
2284 * One of the side effects of the JOIN command is that is clears
2285 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2286 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002287 * Currently the only valid scenario for JOIN during association
2288 * is on roaming, in which case we will also be given new keys.
2289 * Keep the below message for now, unless it starts bothering
2290 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002291 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002292 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002293 wl1271_info("JOIN while associated.");
2294
2295 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002296 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002297
Eliad Peller227e81e2011-08-14 13:17:26 +03002298 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002299 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002300 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002301 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002302 if (ret < 0)
2303 goto out;
2304
Eliad Pellerba8447f2011-10-10 10:13:00 +02002305 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002306 goto out;
2307
2308 /*
2309 * The join command disable the keep-alive mode, shut down its process,
2310 * and also clear the template config, so we need to reset it all after
2311 * the join. The acx_aid starts the keep-alive process, and the order
2312 * of the commands below is relevant.
2313 */
Eliad Peller0603d892011-10-05 11:55:51 +02002314 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002315 if (ret < 0)
2316 goto out;
2317
Eliad Peller0603d892011-10-05 11:55:51 +02002318 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002319 if (ret < 0)
2320 goto out;
2321
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002322 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002323 if (ret < 0)
2324 goto out;
2325
Eliad Peller0603d892011-10-05 11:55:51 +02002326 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2327 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002328 ACX_KEEP_ALIVE_TPL_VALID);
2329 if (ret < 0)
2330 goto out;
2331
2332out:
2333 return ret;
2334}
2335
Eliad Peller0603d892011-10-05 11:55:51 +02002336static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002337{
2338 int ret;
2339
Eliad Peller52630c52011-10-10 10:13:08 +02002340 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002341 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2342
Shahar Levi6d158ff2011-09-08 13:01:33 +03002343 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002344 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002345 }
2346
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002347 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002348 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002349 if (ret < 0)
2350 goto out;
2351
Oz Krakowskib992c682011-06-26 10:36:02 +03002352 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002353 wlvif->tx_security_last_seq_lsb = 0;
2354 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002355
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002356out:
2357 return ret;
2358}
2359
Eliad Peller87fbcb02011-10-05 11:55:41 +02002360static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002361{
Eliad Peller1b92f152011-10-10 10:13:09 +02002362 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002363 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002364}
2365
Eliad Peller251c1772011-08-14 13:17:17 +03002366static bool wl12xx_is_roc(struct wl1271 *wl)
2367{
2368 u8 role_id;
2369
2370 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2371 if (role_id >= WL12XX_MAX_ROLES)
2372 return false;
2373
2374 return true;
2375}
2376
Eliad Peller87fbcb02011-10-05 11:55:41 +02002377static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2378 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002379{
2380 int ret;
2381
2382 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002383 /* no need to croc if we weren't busy (e.g. during boot) */
2384 if (wl12xx_is_roc(wl)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002385 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002386 if (ret < 0)
2387 goto out;
2388 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002389 wlvif->rate_set =
2390 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2391 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002392 if (ret < 0)
2393 goto out;
2394 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002395 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002396 ACX_KEEP_ALIVE_TPL_INVALID);
2397 if (ret < 0)
2398 goto out;
2399 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2400 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002401 /* The current firmware only supports sched_scan in idle */
2402 if (wl->sched_scanning) {
2403 wl1271_scan_sched_scan_stop(wl);
2404 ieee80211_sched_scan_stopped(wl->hw);
2405 }
2406
Eliad Peller679a6732011-10-11 11:55:44 +02002407 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002408 if (ret < 0)
2409 goto out;
2410 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2411 }
2412
2413out:
2414 return ret;
2415}
2416
Eliad Peller9f259c42011-10-10 10:13:12 +02002417static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2418 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002419{
Eliad Peller9f259c42011-10-10 10:13:12 +02002420 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2421 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002422
2423 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2424
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002425 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002426 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002427 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002428 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002429 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002430 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002431 wlvif->band = conf->channel->band;
2432 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002433
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002434 if (!is_ap) {
2435 /*
2436 * FIXME: the mac80211 should really provide a fixed
2437 * rate to use here. for now, just use the smallest
2438 * possible rate for the band as a fixed rate for
2439 * association frames and other control messages.
2440 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002441 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002442 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002443
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002444 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002445 wl1271_tx_min_rate_get(wl,
2446 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002447 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002448 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002449 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002450 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002451
Eliad Pellerba8447f2011-10-10 10:13:00 +02002452 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2453 &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002454 if (wl12xx_is_roc(wl)) {
2455 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002456 ret = wl12xx_croc(wl,
2457 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002458 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002459 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002460 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002461 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002462 if (ret < 0)
2463 wl1271_warning("cmd join on channel "
2464 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002465 } else {
2466 /*
2467 * change the ROC channel. do it only if we are
2468 * not idle. otherwise, CROC will be called
2469 * anyway.
2470 */
2471 if (wl12xx_is_roc(wl) &&
2472 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002473 ret = wl12xx_stop_dev(wl, wlvif);
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 Peller679a6732011-10-11 11:55:44 +02002477 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002478 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002479 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002480 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002481 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002482 }
2483 }
2484
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002485 /*
2486 * if mac80211 changes the PSM mode, make sure the mode is not
2487 * incorrectly changed after the pspoll failure active window.
2488 */
2489 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002490 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002491
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002492 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002493 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2494 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002495
2496 /*
2497 * We enter PSM only if we're already associated.
2498 * If we're not, we'll enter it when joining an SSID,
2499 * through the bss_info_changed() hook.
2500 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002501 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002502 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002503 ret = wl1271_ps_set_mode(wl, wlvif,
2504 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002505 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002506 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002507 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002508 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002509 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002510
Eliad Pellerc29bb002011-10-10 10:13:03 +02002511 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002512
Eliad Pellerc29bb002011-10-10 10:13:03 +02002513 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002514 ret = wl1271_ps_set_mode(wl, wlvif,
2515 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002516 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002517 }
2518
Eliad Peller6bd65022011-10-10 10:13:11 +02002519 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002520 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002521 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002522 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002523
Eliad Peller6bd65022011-10-10 10:13:11 +02002524 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002525 }
2526
Eliad Peller9f259c42011-10-10 10:13:12 +02002527 return 0;
2528}
2529
2530static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2531{
2532 struct wl1271 *wl = hw->priv;
2533 struct wl12xx_vif *wlvif;
2534 struct ieee80211_conf *conf = &hw->conf;
2535 int channel, ret = 0;
2536
2537 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2538
2539 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2540 " changed 0x%x",
2541 channel,
2542 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2543 conf->power_level,
2544 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2545 changed);
2546
2547 /*
2548 * mac80211 will go to idle nearly immediately after transmitting some
2549 * frames, such as the deauth. To make sure those frames reach the air,
2550 * wait here until the TX queue is fully flushed.
2551 */
2552 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2553 (conf->flags & IEEE80211_CONF_IDLE))
2554 wl1271_tx_flush(wl);
2555
2556 mutex_lock(&wl->mutex);
2557
2558 /* we support configuring the channel and band even while off */
2559 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2560 wl->band = conf->channel->band;
2561 wl->channel = channel;
2562 }
2563
2564 if (changed & IEEE80211_CONF_CHANGE_POWER)
2565 wl->power_level = conf->power_level;
2566
2567 if (unlikely(wl->state == WL1271_STATE_OFF))
2568 goto out;
2569
2570 ret = wl1271_ps_elp_wakeup(wl);
2571 if (ret < 0)
2572 goto out;
2573
2574 /* configure each interface */
2575 wl12xx_for_each_wlvif(wl, wlvif) {
2576 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2577 if (ret < 0)
2578 goto out_sleep;
2579 }
2580
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002581out_sleep:
2582 wl1271_ps_elp_sleep(wl);
2583
2584out:
2585 mutex_unlock(&wl->mutex);
2586
2587 return ret;
2588}
2589
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002590struct wl1271_filter_params {
2591 bool enabled;
2592 int mc_list_length;
2593 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2594};
2595
Jiri Pirko22bedad2010-04-01 21:22:57 +00002596static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2597 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002598{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002599 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002600 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002601 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002602
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002603 if (unlikely(wl->state == WL1271_STATE_OFF))
2604 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002605
Juuso Oikarinen74441132009-10-13 12:47:53 +03002606 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002607 if (!fp) {
2608 wl1271_error("Out of memory setting filters.");
2609 return 0;
2610 }
2611
2612 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002613 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002614 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2615 fp->enabled = false;
2616 } else {
2617 fp->enabled = true;
2618 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002619 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002620 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002621 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002622 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002623 }
2624
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002625 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002626}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002627
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002628#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2629 FIF_ALLMULTI | \
2630 FIF_FCSFAIL | \
2631 FIF_BCN_PRBRESP_PROMISC | \
2632 FIF_CONTROL | \
2633 FIF_OTHER_BSS)
2634
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002635static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2636 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002637 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002638{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002639 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002640 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002641 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002642
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002643 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002644
Arik Nemtsov7d057862010-10-16 19:25:35 +02002645 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2646 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002647
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002648 mutex_lock(&wl->mutex);
2649
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002650 *total &= WL1271_SUPPORTED_FILTERS;
2651 changed &= WL1271_SUPPORTED_FILTERS;
2652
2653 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002654 goto out;
2655
Ido Yariva6208652011-03-01 15:14:41 +02002656 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002657 if (ret < 0)
2658 goto out;
2659
Eliad Peller6e8cd332011-10-10 10:13:13 +02002660 wl12xx_for_each_wlvif(wl, wlvif) {
2661 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2662 if (*total & FIF_ALLMULTI)
2663 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2664 false,
2665 NULL, 0);
2666 else if (fp)
2667 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2668 fp->enabled,
2669 fp->mc_list,
2670 fp->mc_list_length);
2671 if (ret < 0)
2672 goto out_sleep;
2673 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002674 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002675
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002676 /*
2677 * the fw doesn't provide an api to configure the filters. instead,
2678 * the filters configuration is based on the active roles / ROC
2679 * state.
2680 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002681
2682out_sleep:
2683 wl1271_ps_elp_sleep(wl);
2684
2685out:
2686 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002687 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002688}
2689
Eliad Peller170d0e62011-10-05 11:56:06 +02002690static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2691 u8 id, u8 key_type, u8 key_size,
2692 const u8 *key, u8 hlid, u32 tx_seq_32,
2693 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002694{
2695 struct wl1271_ap_key *ap_key;
2696 int i;
2697
2698 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2699
2700 if (key_size > MAX_KEY_SIZE)
2701 return -EINVAL;
2702
2703 /*
2704 * Find next free entry in ap_keys. Also check we are not replacing
2705 * an existing key.
2706 */
2707 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002708 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002709 break;
2710
Eliad Peller170d0e62011-10-05 11:56:06 +02002711 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002712 wl1271_warning("trying to record key replacement");
2713 return -EINVAL;
2714 }
2715 }
2716
2717 if (i == MAX_NUM_KEYS)
2718 return -EBUSY;
2719
2720 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2721 if (!ap_key)
2722 return -ENOMEM;
2723
2724 ap_key->id = id;
2725 ap_key->key_type = key_type;
2726 ap_key->key_size = key_size;
2727 memcpy(ap_key->key, key, key_size);
2728 ap_key->hlid = hlid;
2729 ap_key->tx_seq_32 = tx_seq_32;
2730 ap_key->tx_seq_16 = tx_seq_16;
2731
Eliad Peller170d0e62011-10-05 11:56:06 +02002732 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002733 return 0;
2734}
2735
Eliad Peller170d0e62011-10-05 11:56:06 +02002736static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002737{
2738 int i;
2739
2740 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002741 kfree(wlvif->ap.recorded_keys[i]);
2742 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002743 }
2744}
2745
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002746static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002747{
2748 int i, ret = 0;
2749 struct wl1271_ap_key *key;
2750 bool wep_key_added = false;
2751
2752 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002753 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002754 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002755 break;
2756
Eliad Peller170d0e62011-10-05 11:56:06 +02002757 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002758 hlid = key->hlid;
2759 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002760 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002761
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002762 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002763 key->id, key->key_type,
2764 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002765 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002766 key->tx_seq_16);
2767 if (ret < 0)
2768 goto out;
2769
2770 if (key->key_type == KEY_WEP)
2771 wep_key_added = true;
2772 }
2773
2774 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002775 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002776 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002777 if (ret < 0)
2778 goto out;
2779 }
2780
2781out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002782 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002783 return ret;
2784}
2785
Eliad Peller536129c2011-10-05 11:55:45 +02002786static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2787 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002788 u8 key_size, const u8 *key, u32 tx_seq_32,
2789 u16 tx_seq_16, struct ieee80211_sta *sta)
2790{
2791 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002792 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002793
2794 if (is_ap) {
2795 struct wl1271_station *wl_sta;
2796 u8 hlid;
2797
2798 if (sta) {
2799 wl_sta = (struct wl1271_station *)sta->drv_priv;
2800 hlid = wl_sta->hlid;
2801 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002802 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002803 }
2804
Eliad Peller53d40d02011-10-10 10:13:02 +02002805 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002806 /*
2807 * We do not support removing keys after AP shutdown.
2808 * Pretend we do to make mac80211 happy.
2809 */
2810 if (action != KEY_ADD_OR_REPLACE)
2811 return 0;
2812
Eliad Peller170d0e62011-10-05 11:56:06 +02002813 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002814 key_type, key_size,
2815 key, hlid, tx_seq_32,
2816 tx_seq_16);
2817 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002818 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002819 id, key_type, key_size,
2820 key, hlid, tx_seq_32,
2821 tx_seq_16);
2822 }
2823
2824 if (ret < 0)
2825 return ret;
2826 } else {
2827 const u8 *addr;
2828 static const u8 bcast_addr[ETH_ALEN] = {
2829 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2830 };
2831
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002832 /*
2833 * A STA set to GEM cipher requires 2 tx spare blocks.
2834 * Return to default value when GEM cipher key is removed
2835 */
2836 if (key_type == KEY_GEM) {
2837 if (action == KEY_ADD_OR_REPLACE)
2838 wl->tx_spare_blocks = 2;
2839 else if (action == KEY_REMOVE)
2840 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2841 }
2842
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002843 addr = sta ? sta->addr : bcast_addr;
2844
2845 if (is_zero_ether_addr(addr)) {
2846 /* We dont support TX only encryption */
2847 return -EOPNOTSUPP;
2848 }
2849
2850 /* The wl1271 does not allow to remove unicast keys - they
2851 will be cleared automatically on next CMD_JOIN. Ignore the
2852 request silently, as we dont want the mac80211 to emit
2853 an error message. */
2854 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2855 return 0;
2856
Eliad Peller010d3d32011-08-14 13:17:31 +03002857 /* don't remove key if hlid was already deleted */
2858 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002859 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002860 return 0;
2861
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002862 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002863 id, key_type, key_size,
2864 key, addr, tx_seq_32,
2865 tx_seq_16);
2866 if (ret < 0)
2867 return ret;
2868
2869 /* the default WEP key needs to be configured at least once */
2870 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002871 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002872 wlvif->default_key,
2873 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002874 if (ret < 0)
2875 return ret;
2876 }
2877 }
2878
2879 return 0;
2880}
2881
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002882static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2883 struct ieee80211_vif *vif,
2884 struct ieee80211_sta *sta,
2885 struct ieee80211_key_conf *key_conf)
2886{
2887 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002888 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002889 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002890 u32 tx_seq_32 = 0;
2891 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002892 u8 key_type;
2893
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002894 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2895
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002896 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002897 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002898 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002899 key_conf->keylen, key_conf->flags);
2900 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2901
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002902 mutex_lock(&wl->mutex);
2903
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002904 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2905 ret = -EAGAIN;
2906 goto out_unlock;
2907 }
2908
Ido Yariva6208652011-03-01 15:14:41 +02002909 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002910 if (ret < 0)
2911 goto out_unlock;
2912
Johannes Berg97359d12010-08-10 09:46:38 +02002913 switch (key_conf->cipher) {
2914 case WLAN_CIPHER_SUITE_WEP40:
2915 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002916 key_type = KEY_WEP;
2917
2918 key_conf->hw_key_idx = key_conf->keyidx;
2919 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002920 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002921 key_type = KEY_TKIP;
2922
2923 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002924 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2925 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002926 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002927 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002928 key_type = KEY_AES;
2929
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002930 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002931 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2932 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002933 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002934 case WL1271_CIPHER_SUITE_GEM:
2935 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002936 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2937 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002938 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002939 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002940 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002941
2942 ret = -EOPNOTSUPP;
2943 goto out_sleep;
2944 }
2945
2946 switch (cmd) {
2947 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002948 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002949 key_conf->keyidx, key_type,
2950 key_conf->keylen, key_conf->key,
2951 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002952 if (ret < 0) {
2953 wl1271_error("Could not add or replace key");
2954 goto out_sleep;
2955 }
2956 break;
2957
2958 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002959 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002960 key_conf->keyidx, key_type,
2961 key_conf->keylen, key_conf->key,
2962 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002963 if (ret < 0) {
2964 wl1271_error("Could not remove key");
2965 goto out_sleep;
2966 }
2967 break;
2968
2969 default:
2970 wl1271_error("Unsupported key cmd 0x%x", cmd);
2971 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002972 break;
2973 }
2974
2975out_sleep:
2976 wl1271_ps_elp_sleep(wl);
2977
2978out_unlock:
2979 mutex_unlock(&wl->mutex);
2980
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002981 return ret;
2982}
2983
2984static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002985 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002986 struct cfg80211_scan_request *req)
2987{
2988 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02002989 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2990
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002991 int ret;
2992 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002993 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002994
2995 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2996
2997 if (req->n_ssids) {
2998 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002999 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003000 }
3001
3002 mutex_lock(&wl->mutex);
3003
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003004 if (wl->state == WL1271_STATE_OFF) {
3005 /*
3006 * We cannot return -EBUSY here because cfg80211 will expect
3007 * a call to ieee80211_scan_completed if we do - in this case
3008 * there won't be any call.
3009 */
3010 ret = -EAGAIN;
3011 goto out;
3012 }
3013
Ido Yariva6208652011-03-01 15:14:41 +02003014 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003015 if (ret < 0)
3016 goto out;
3017
Eliad Peller251c1772011-08-14 13:17:17 +03003018 /* cancel ROC before scanning */
3019 if (wl12xx_is_roc(wl)) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02003020 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Eliad Peller251c1772011-08-14 13:17:17 +03003021 /* don't allow scanning right now */
3022 ret = -EBUSY;
3023 goto out_sleep;
3024 }
Eliad Peller679a6732011-10-11 11:55:44 +02003025 wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003026 }
3027
Eliad Peller784f6942011-10-05 11:55:39 +02003028 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003029out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003030 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003031out:
3032 mutex_unlock(&wl->mutex);
3033
3034 return ret;
3035}
3036
Eliad Peller73ecce32011-06-27 13:06:45 +03003037static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3038 struct ieee80211_vif *vif)
3039{
3040 struct wl1271 *wl = hw->priv;
3041 int ret;
3042
3043 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3044
3045 mutex_lock(&wl->mutex);
3046
3047 if (wl->state == WL1271_STATE_OFF)
3048 goto out;
3049
3050 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3051 goto out;
3052
3053 ret = wl1271_ps_elp_wakeup(wl);
3054 if (ret < 0)
3055 goto out;
3056
3057 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3058 ret = wl1271_scan_stop(wl);
3059 if (ret < 0)
3060 goto out_sleep;
3061 }
3062 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3063 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003064 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003065 wl->scan.req = NULL;
3066 ieee80211_scan_completed(wl->hw, true);
3067
3068out_sleep:
3069 wl1271_ps_elp_sleep(wl);
3070out:
3071 mutex_unlock(&wl->mutex);
3072
3073 cancel_delayed_work_sync(&wl->scan_complete_work);
3074}
3075
Luciano Coelho33c2c062011-05-10 14:46:02 +03003076static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3077 struct ieee80211_vif *vif,
3078 struct cfg80211_sched_scan_request *req,
3079 struct ieee80211_sched_scan_ies *ies)
3080{
3081 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003082 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003083 int ret;
3084
3085 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3086
3087 mutex_lock(&wl->mutex);
3088
3089 ret = wl1271_ps_elp_wakeup(wl);
3090 if (ret < 0)
3091 goto out;
3092
Eliad Peller536129c2011-10-05 11:55:45 +02003093 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003094 if (ret < 0)
3095 goto out_sleep;
3096
Eliad Peller536129c2011-10-05 11:55:45 +02003097 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003098 if (ret < 0)
3099 goto out_sleep;
3100
3101 wl->sched_scanning = true;
3102
3103out_sleep:
3104 wl1271_ps_elp_sleep(wl);
3105out:
3106 mutex_unlock(&wl->mutex);
3107 return ret;
3108}
3109
3110static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3111 struct ieee80211_vif *vif)
3112{
3113 struct wl1271 *wl = hw->priv;
3114 int ret;
3115
3116 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3117
3118 mutex_lock(&wl->mutex);
3119
3120 ret = wl1271_ps_elp_wakeup(wl);
3121 if (ret < 0)
3122 goto out;
3123
3124 wl1271_scan_sched_scan_stop(wl);
3125
3126 wl1271_ps_elp_sleep(wl);
3127out:
3128 mutex_unlock(&wl->mutex);
3129}
3130
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003131static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3132{
3133 struct wl1271 *wl = hw->priv;
3134 int ret = 0;
3135
3136 mutex_lock(&wl->mutex);
3137
3138 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3139 ret = -EAGAIN;
3140 goto out;
3141 }
3142
Ido Yariva6208652011-03-01 15:14:41 +02003143 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003144 if (ret < 0)
3145 goto out;
3146
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003147 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003148 if (ret < 0)
3149 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3150
3151 wl1271_ps_elp_sleep(wl);
3152
3153out:
3154 mutex_unlock(&wl->mutex);
3155
3156 return ret;
3157}
3158
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003159static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3160{
3161 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003162 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003163 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003164
3165 mutex_lock(&wl->mutex);
3166
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003167 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3168 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003169 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003170 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003171
Ido Yariva6208652011-03-01 15:14:41 +02003172 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003173 if (ret < 0)
3174 goto out;
3175
Eliad Peller6e8cd332011-10-10 10:13:13 +02003176 wl12xx_for_each_wlvif(wl, wlvif) {
3177 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3178 if (ret < 0)
3179 wl1271_warning("set rts threshold failed: %d", ret);
3180 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003181 wl1271_ps_elp_sleep(wl);
3182
3183out:
3184 mutex_unlock(&wl->mutex);
3185
3186 return ret;
3187}
3188
Eliad Peller1fe9f162011-10-05 11:55:48 +02003189static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003190 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003191{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003192 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003193 u8 ssid_len;
3194 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3195 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003196
Eliad Peller889cb362011-05-01 09:56:45 +03003197 if (!ptr) {
3198 wl1271_error("No SSID in IEs!");
3199 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003200 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003201
Eliad Peller889cb362011-05-01 09:56:45 +03003202 ssid_len = ptr[1];
3203 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3204 wl1271_error("SSID is too long!");
3205 return -EINVAL;
3206 }
3207
Eliad Peller1fe9f162011-10-05 11:55:48 +02003208 wlvif->ssid_len = ssid_len;
3209 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003210 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003211}
3212
Eliad Pellerd48055d2011-09-15 12:07:04 +03003213static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3214{
3215 int len;
3216 const u8 *next, *end = skb->data + skb->len;
3217 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3218 skb->len - ieoffset);
3219 if (!ie)
3220 return;
3221 len = ie[1] + 2;
3222 next = ie + len;
3223 memmove(ie, next, end - next);
3224 skb_trim(skb, skb->len - len);
3225}
3226
Eliad Peller26b4bf22011-09-15 12:07:05 +03003227static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3228 unsigned int oui, u8 oui_type,
3229 int ieoffset)
3230{
3231 int len;
3232 const u8 *next, *end = skb->data + skb->len;
3233 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3234 skb->data + ieoffset,
3235 skb->len - ieoffset);
3236 if (!ie)
3237 return;
3238 len = ie[1] + 2;
3239 next = ie + len;
3240 memmove(ie, next, end - next);
3241 skb_trim(skb, skb->len - len);
3242}
3243
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003244static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3245 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003246{
3247 struct sk_buff *skb;
3248 int ret;
3249
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003250 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003251 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003252 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003253
3254 ret = wl1271_cmd_template_set(wl,
3255 CMD_TEMPL_AP_PROBE_RESPONSE,
3256 skb->data,
3257 skb->len, 0,
3258 rates);
3259
3260 dev_kfree_skb(skb);
3261 return ret;
3262}
3263
3264static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3265 struct ieee80211_vif *vif,
3266 u8 *probe_rsp_data,
3267 size_t probe_rsp_len,
3268 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003269{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003270 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3271 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003272 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3273 int ssid_ie_offset, ie_offset, templ_len;
3274 const u8 *ptr;
3275
3276 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003277 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003278 return wl1271_cmd_template_set(wl,
3279 CMD_TEMPL_AP_PROBE_RESPONSE,
3280 probe_rsp_data,
3281 probe_rsp_len, 0,
3282 rates);
3283
3284 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3285 wl1271_error("probe_rsp template too big");
3286 return -EINVAL;
3287 }
3288
3289 /* start searching from IE offset */
3290 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3291
3292 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3293 probe_rsp_len - ie_offset);
3294 if (!ptr) {
3295 wl1271_error("No SSID in beacon!");
3296 return -EINVAL;
3297 }
3298
3299 ssid_ie_offset = ptr - probe_rsp_data;
3300 ptr += (ptr[1] + 2);
3301
3302 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3303
3304 /* insert SSID from bss_conf */
3305 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3306 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3307 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3308 bss_conf->ssid, bss_conf->ssid_len);
3309 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3310
3311 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3312 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3313 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3314
3315 return wl1271_cmd_template_set(wl,
3316 CMD_TEMPL_AP_PROBE_RESPONSE,
3317 probe_rsp_templ,
3318 templ_len, 0,
3319 rates);
3320}
3321
Arik Nemtsove78a2872010-10-16 19:07:21 +02003322static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003323 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003324 struct ieee80211_bss_conf *bss_conf,
3325 u32 changed)
3326{
Eliad Peller0603d892011-10-05 11:55:51 +02003327 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003328 int ret = 0;
3329
3330 if (changed & BSS_CHANGED_ERP_SLOT) {
3331 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003332 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003333 else
Eliad Peller0603d892011-10-05 11:55:51 +02003334 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003335 if (ret < 0) {
3336 wl1271_warning("Set slot time failed %d", ret);
3337 goto out;
3338 }
3339 }
3340
3341 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3342 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003343 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003344 else
Eliad Peller0603d892011-10-05 11:55:51 +02003345 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003346 }
3347
3348 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3349 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003350 ret = wl1271_acx_cts_protect(wl, wlvif,
3351 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003352 else
Eliad Peller0603d892011-10-05 11:55:51 +02003353 ret = wl1271_acx_cts_protect(wl, wlvif,
3354 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003355 if (ret < 0) {
3356 wl1271_warning("Set ctsprotect failed %d", ret);
3357 goto out;
3358 }
3359 }
3360
3361out:
3362 return ret;
3363}
3364
3365static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3366 struct ieee80211_vif *vif,
3367 struct ieee80211_bss_conf *bss_conf,
3368 u32 changed)
3369{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003370 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003371 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003372 int ret = 0;
3373
3374 if ((changed & BSS_CHANGED_BEACON_INT)) {
3375 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3376 bss_conf->beacon_int);
3377
Eliad Peller6a899792011-10-05 11:55:58 +02003378 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003379 }
3380
Arik Nemtsov560f0022011-11-08 18:46:54 +02003381 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3382 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003383 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3384 wl1271_debug(DEBUG_AP, "probe response updated");
3385 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3386 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003387 }
3388
Arik Nemtsove78a2872010-10-16 19:07:21 +02003389 if ((changed & BSS_CHANGED_BEACON)) {
3390 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003391 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003392 int ieoffset = offsetof(struct ieee80211_mgmt,
3393 u.beacon.variable);
3394 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3395 u16 tmpl_id;
3396
Arik Nemtsov560f0022011-11-08 18:46:54 +02003397 if (!beacon) {
3398 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003399 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003400 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003401
3402 wl1271_debug(DEBUG_MASTER, "beacon updated");
3403
Eliad Peller1fe9f162011-10-05 11:55:48 +02003404 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003405 if (ret < 0) {
3406 dev_kfree_skb(beacon);
3407 goto out;
3408 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003409 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003410 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3411 CMD_TEMPL_BEACON;
3412 ret = wl1271_cmd_template_set(wl, tmpl_id,
3413 beacon->data,
3414 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003415 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003416 if (ret < 0) {
3417 dev_kfree_skb(beacon);
3418 goto out;
3419 }
3420
Arik Nemtsov560f0022011-11-08 18:46:54 +02003421 /*
3422 * In case we already have a probe-resp beacon set explicitly
3423 * by usermode, don't use the beacon data.
3424 */
3425 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3426 goto end_bcn;
3427
Eliad Pellerd48055d2011-09-15 12:07:04 +03003428 /* remove TIM ie from probe response */
3429 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3430
Eliad Peller26b4bf22011-09-15 12:07:05 +03003431 /*
3432 * remove p2p ie from probe response.
3433 * the fw reponds to probe requests that don't include
3434 * the p2p ie. probe requests with p2p ie will be passed,
3435 * and will be responded by the supplicant (the spec
3436 * forbids including the p2p ie when responding to probe
3437 * requests that didn't include it).
3438 */
3439 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3440 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3441
Arik Nemtsove78a2872010-10-16 19:07:21 +02003442 hdr = (struct ieee80211_hdr *) beacon->data;
3443 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3444 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003445 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003446 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003447 beacon->data,
3448 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003449 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003450 else
3451 ret = wl1271_cmd_template_set(wl,
3452 CMD_TEMPL_PROBE_RESPONSE,
3453 beacon->data,
3454 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003455 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003456end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003457 dev_kfree_skb(beacon);
3458 if (ret < 0)
3459 goto out;
3460 }
3461
3462out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003463 if (ret != 0)
3464 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003465 return ret;
3466}
3467
3468/* AP mode changes */
3469static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003470 struct ieee80211_vif *vif,
3471 struct ieee80211_bss_conf *bss_conf,
3472 u32 changed)
3473{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003474 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003475 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003476
Arik Nemtsove78a2872010-10-16 19:07:21 +02003477 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3478 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003479
Eliad Peller87fbcb02011-10-05 11:55:41 +02003480 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003481 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003482 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003483 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003484
Eliad Peller87fbcb02011-10-05 11:55:41 +02003485 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003486 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003487 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003488 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003489 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003490
Eliad Peller784f6942011-10-05 11:55:39 +02003491 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003492 if (ret < 0)
3493 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003494 }
3495
Arik Nemtsove78a2872010-10-16 19:07:21 +02003496 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3497 if (ret < 0)
3498 goto out;
3499
3500 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3501 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003502 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003503 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003504 if (ret < 0)
3505 goto out;
3506
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003507 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003508 if (ret < 0)
3509 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003510
Eliad Peller53d40d02011-10-10 10:13:02 +02003511 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003512 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003513 }
3514 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003515 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003516 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003517 if (ret < 0)
3518 goto out;
3519
Eliad Peller53d40d02011-10-10 10:13:02 +02003520 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003521 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3522 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003523 wl1271_debug(DEBUG_AP, "stopped AP");
3524 }
3525 }
3526 }
3527
Eliad Peller0603d892011-10-05 11:55:51 +02003528 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003529 if (ret < 0)
3530 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003531
3532 /* Handle HT information change */
3533 if ((changed & BSS_CHANGED_HT) &&
3534 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003535 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003536 bss_conf->ht_operation_mode);
3537 if (ret < 0) {
3538 wl1271_warning("Set ht information failed %d", ret);
3539 goto out;
3540 }
3541 }
3542
Arik Nemtsove78a2872010-10-16 19:07:21 +02003543out:
3544 return;
3545}
3546
3547/* STA/IBSS mode changes */
3548static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3549 struct ieee80211_vif *vif,
3550 struct ieee80211_bss_conf *bss_conf,
3551 u32 changed)
3552{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003553 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003554 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003555 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003556 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003557 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003558 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003559 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003560 bool sta_exists = false;
3561 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003562
3563 if (is_ibss) {
3564 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3565 changed);
3566 if (ret < 0)
3567 goto out;
3568 }
3569
Eliad Peller227e81e2011-08-14 13:17:26 +03003570 if (changed & BSS_CHANGED_IBSS) {
3571 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003572 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003573 ibss_joined = true;
3574 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003575 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3576 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003577 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003578 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003579 }
3580 }
3581 }
3582
3583 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003584 do_join = true;
3585
3586 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003587 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003588 do_join = true;
3589
Eliad Peller227e81e2011-08-14 13:17:26 +03003590 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003591 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3592 bss_conf->enable_beacon ? "enabled" : "disabled");
3593
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003594 do_join = true;
3595 }
3596
Eliad Pellerc31e4942011-10-23 08:21:55 +02003597 if (changed & BSS_CHANGED_IDLE) {
3598 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3599 if (ret < 0)
3600 wl1271_warning("idle mode change failed %d", ret);
3601 }
3602
Arik Nemtsove78a2872010-10-16 19:07:21 +02003603 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003604 bool enable = false;
3605 if (bss_conf->cqm_rssi_thold)
3606 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003607 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003608 bss_conf->cqm_rssi_thold,
3609 bss_conf->cqm_rssi_hyst);
3610 if (ret < 0)
3611 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003612 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003613 }
3614
Eliad Pellercdf09492011-10-05 11:55:44 +02003615 if (changed & BSS_CHANGED_BSSID)
3616 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003617 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003618 if (ret < 0)
3619 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003620
Eliad Peller784f6942011-10-05 11:55:39 +02003621 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003622 if (ret < 0)
3623 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003624
Eliad Pellerfa287b82010-12-26 09:27:50 +01003625 /* Need to update the BSSID (for filtering etc) */
3626 do_join = true;
3627 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003628
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003629 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3630 rcu_read_lock();
3631 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3632 if (!sta)
3633 goto sta_not_found;
3634
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003635 /* save the supp_rates of the ap */
3636 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3637 if (sta->ht_cap.ht_supported)
3638 sta_rate_set |=
3639 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003640 sta_ht_cap = sta->ht_cap;
3641 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003642
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003643sta_not_found:
3644 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003645 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003646
Arik Nemtsove78a2872010-10-16 19:07:21 +02003647 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003648 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003649 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003650 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003651 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003652 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003653
Eliad Peller74ec8392011-10-05 11:56:02 +02003654 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003655
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003656 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003657 * use basic rates from AP, and determine lowest rate
3658 * to use with control frames.
3659 */
3660 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003661 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003662 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003663 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003664 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003665 wl1271_tx_min_rate_get(wl,
3666 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003667 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003668 wlvif->rate_set =
3669 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003670 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003671 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003672 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003673 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003674 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003675
3676 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003677 * with wl1271, we don't need to update the
3678 * beacon_int and dtim_period, because the firmware
3679 * updates it by itself when the first beacon is
3680 * received after a join.
3681 */
Eliad Peller6840e372011-10-05 11:55:50 +02003682 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003683 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003684 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003685
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003686 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003687 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003688 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003689 dev_kfree_skb(wlvif->probereq);
3690 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003691 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003692 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003693 ieoffset = offsetof(struct ieee80211_mgmt,
3694 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003695 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003696
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003697 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003698 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003699 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003700 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003701 } else {
3702 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003703 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003704 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3705 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003706 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003707 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3708 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003709 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003710
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003711 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003712 dev_kfree_skb(wlvif->probereq);
3713 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003714
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003715 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003716 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003717
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003718 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003719 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003720 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003721 wl1271_tx_min_rate_get(wl,
3722 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003723 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003724 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003725 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003726
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003727 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003728 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003729
3730 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003731 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003732 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003733 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003734
3735 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003736 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003737 u32 conf_flags = wl->hw->conf.flags;
3738 /*
3739 * we might have to disable roc, if there was
3740 * no IF_OPER_UP notification.
3741 */
3742 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003743 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003744 if (ret < 0)
3745 goto out;
3746 }
3747 /*
3748 * (we also need to disable roc in case of
3749 * roaming on the same channel. until we will
3750 * have a better flow...)
3751 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003752 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3753 ret = wl12xx_croc(wl,
3754 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003755 if (ret < 0)
3756 goto out;
3757 }
3758
Eliad Peller0603d892011-10-05 11:55:51 +02003759 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003760 if (!(conf_flags & IEEE80211_CONF_IDLE))
3761 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003762 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003763 }
3764 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003765
Eliad Pellerd192d262011-05-24 14:33:08 +03003766 if (changed & BSS_CHANGED_IBSS) {
3767 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3768 bss_conf->ibss_joined);
3769
3770 if (bss_conf->ibss_joined) {
3771 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003772 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003773 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003774 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003775 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003776 wl1271_tx_min_rate_get(wl,
3777 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003778
Shahar Levi06b660e2011-09-05 13:54:36 +03003779 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003780 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3781 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003782 if (ret < 0)
3783 goto out;
3784 }
3785 }
3786
Eliad Peller0603d892011-10-05 11:55:51 +02003787 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003788 if (ret < 0)
3789 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003790
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003791 if (changed & BSS_CHANGED_ARP_FILTER) {
3792 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003793 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003794
Eliad Pellerc5312772010-12-09 11:31:27 +02003795 if (bss_conf->arp_addr_cnt == 1 &&
3796 bss_conf->arp_filter_enabled) {
3797 /*
3798 * The template should have been configured only upon
3799 * association. however, it seems that the correct ip
3800 * isn't being set (when sending), so we have to
3801 * reconfigure the template upon every ip change.
3802 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003803 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003804 if (ret < 0) {
3805 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003806 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003807 }
3808
Eliad Peller0603d892011-10-05 11:55:51 +02003809 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003810 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003811 addr);
3812 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003813 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003814
3815 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003816 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003817 }
3818
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003819 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003820 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003821 if (ret < 0) {
3822 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003823 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003824 }
Eliad Peller251c1772011-08-14 13:17:17 +03003825
3826 /* ROC until connected (after EAPOL exchange) */
3827 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003828 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003829 if (ret < 0)
3830 goto out;
3831
Eliad Pellerba8447f2011-10-10 10:13:00 +02003832 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003833 ieee80211_get_operstate(vif));
3834 }
3835 /*
3836 * stop device role if started (we might already be in
3837 * STA role). TODO: make it better.
3838 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003839 if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) {
Eliad Peller679a6732011-10-11 11:55:44 +02003840 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003841 if (ret < 0)
3842 goto out;
3843 }
Eliad Peller05dba352011-08-23 16:37:01 +03003844
3845 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003846 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3847 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003848 enum wl1271_cmd_ps_mode mode;
3849
3850 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003851 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003852 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003853 true);
3854 if (ret < 0)
3855 goto out;
3856 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003857 }
3858
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003859 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003860 if (sta_exists) {
3861 if ((changed & BSS_CHANGED_HT) &&
3862 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003863 ret = wl1271_acx_set_ht_capabilities(wl,
3864 &sta_ht_cap,
3865 true,
Eliad Peller154da672011-10-05 11:55:53 +02003866 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003867 if (ret < 0) {
3868 wl1271_warning("Set ht cap true failed %d",
3869 ret);
3870 goto out;
3871 }
3872 }
3873 /* handle new association without HT and disassociation */
3874 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003875 ret = wl1271_acx_set_ht_capabilities(wl,
3876 &sta_ht_cap,
3877 false,
Eliad Peller154da672011-10-05 11:55:53 +02003878 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003879 if (ret < 0) {
3880 wl1271_warning("Set ht cap false failed %d",
3881 ret);
3882 goto out;
3883 }
3884 }
3885 }
3886
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003887 /* Handle HT information change. Done after join. */
3888 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003889 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003890 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003891 bss_conf->ht_operation_mode);
3892 if (ret < 0) {
3893 wl1271_warning("Set ht information failed %d", ret);
3894 goto out;
3895 }
3896 }
3897
Arik Nemtsove78a2872010-10-16 19:07:21 +02003898out:
3899 return;
3900}
3901
3902static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3903 struct ieee80211_vif *vif,
3904 struct ieee80211_bss_conf *bss_conf,
3905 u32 changed)
3906{
3907 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003908 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3909 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003910 int ret;
3911
3912 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3913 (int)changed);
3914
3915 mutex_lock(&wl->mutex);
3916
3917 if (unlikely(wl->state == WL1271_STATE_OFF))
3918 goto out;
3919
Eliad Peller10c8cd02011-10-10 10:13:06 +02003920 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3921 goto out;
3922
Ido Yariva6208652011-03-01 15:14:41 +02003923 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003924 if (ret < 0)
3925 goto out;
3926
3927 if (is_ap)
3928 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3929 else
3930 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3931
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003932 wl1271_ps_elp_sleep(wl);
3933
3934out:
3935 mutex_unlock(&wl->mutex);
3936}
3937
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003938static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3939 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003940 const struct ieee80211_tx_queue_params *params)
3941{
3942 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003943 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003944 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003945 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003946
3947 mutex_lock(&wl->mutex);
3948
3949 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3950
Kalle Valo4695dc92010-03-18 12:26:38 +02003951 if (params->uapsd)
3952 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3953 else
3954 ps_scheme = CONF_PS_SCHEME_LEGACY;
3955
Arik Nemtsov488fc542010-10-16 20:33:45 +02003956 if (wl->state == WL1271_STATE_OFF) {
3957 /*
3958 * If the state is off, the parameters will be recorded and
3959 * configured on init. This happens in AP-mode.
3960 */
3961 struct conf_tx_ac_category *conf_ac =
3962 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3963 struct conf_tx_tid *conf_tid =
3964 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3965
3966 conf_ac->ac = wl1271_tx_get_queue(queue);
3967 conf_ac->cw_min = (u8)params->cw_min;
3968 conf_ac->cw_max = params->cw_max;
3969 conf_ac->aifsn = params->aifs;
3970 conf_ac->tx_op_limit = params->txop << 5;
3971
3972 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3973 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3974 conf_tid->tsid = wl1271_tx_get_queue(queue);
3975 conf_tid->ps_scheme = ps_scheme;
3976 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3977 conf_tid->apsd_conf[0] = 0;
3978 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003979 goto out;
3980 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003981
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003982 ret = wl1271_ps_elp_wakeup(wl);
3983 if (ret < 0)
3984 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003985
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003986 /*
3987 * the txop is confed in units of 32us by the mac80211,
3988 * we need us
3989 */
Eliad Peller0603d892011-10-05 11:55:51 +02003990 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003991 params->cw_min, params->cw_max,
3992 params->aifs, params->txop << 5);
3993 if (ret < 0)
3994 goto out_sleep;
3995
Eliad Peller0603d892011-10-05 11:55:51 +02003996 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003997 CONF_CHANNEL_TYPE_EDCF,
3998 wl1271_tx_get_queue(queue),
3999 ps_scheme, CONF_ACK_POLICY_LEGACY,
4000 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004001
4002out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004003 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004004
4005out:
4006 mutex_unlock(&wl->mutex);
4007
4008 return ret;
4009}
4010
Eliad Peller37a41b42011-09-21 14:06:11 +03004011static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4012 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004013{
4014
4015 struct wl1271 *wl = hw->priv;
4016 u64 mactime = ULLONG_MAX;
4017 int ret;
4018
4019 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4020
4021 mutex_lock(&wl->mutex);
4022
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004023 if (unlikely(wl->state == WL1271_STATE_OFF))
4024 goto out;
4025
Ido Yariva6208652011-03-01 15:14:41 +02004026 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004027 if (ret < 0)
4028 goto out;
4029
4030 ret = wl1271_acx_tsf_info(wl, &mactime);
4031 if (ret < 0)
4032 goto out_sleep;
4033
4034out_sleep:
4035 wl1271_ps_elp_sleep(wl);
4036
4037out:
4038 mutex_unlock(&wl->mutex);
4039 return mactime;
4040}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004041
John W. Linvilleece550d2010-07-28 16:41:06 -04004042static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4043 struct survey_info *survey)
4044{
4045 struct wl1271 *wl = hw->priv;
4046 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004047
John W. Linvilleece550d2010-07-28 16:41:06 -04004048 if (idx != 0)
4049 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004050
John W. Linvilleece550d2010-07-28 16:41:06 -04004051 survey->channel = conf->channel;
4052 survey->filled = SURVEY_INFO_NOISE_DBM;
4053 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004054
John W. Linvilleece550d2010-07-28 16:41:06 -04004055 return 0;
4056}
4057
Arik Nemtsov409622e2011-02-23 00:22:29 +02004058static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004059 struct wl12xx_vif *wlvif,
4060 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004061{
4062 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004063 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004064
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004065
4066 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004067 wl1271_warning("could not allocate HLID - too much stations");
4068 return -EBUSY;
4069 }
4070
4071 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004072 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4073 if (ret < 0) {
4074 wl1271_warning("could not allocate HLID - too many links");
4075 return -EBUSY;
4076 }
4077
4078 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004079 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004080 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004081 return 0;
4082}
4083
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004084void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004085{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004086 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004087 return;
4088
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004089 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004090 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004091 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004092 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004093 __clear_bit(hlid, &wl->ap_ps_map);
4094 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004095 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004096 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004097}
4098
4099static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4100 struct ieee80211_vif *vif,
4101 struct ieee80211_sta *sta)
4102{
4103 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004104 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004105 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004106 int ret = 0;
4107 u8 hlid;
4108
4109 mutex_lock(&wl->mutex);
4110
4111 if (unlikely(wl->state == WL1271_STATE_OFF))
4112 goto out;
4113
Eliad Peller536129c2011-10-05 11:55:45 +02004114 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004115 goto out;
4116
4117 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4118
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004119 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004120 if (ret < 0)
4121 goto out;
4122
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004123 wl_sta = (struct wl1271_station *)sta->drv_priv;
4124 hlid = wl_sta->hlid;
4125
Ido Yariva6208652011-03-01 15:14:41 +02004126 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004127 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004128 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004129
Eliad Peller1b92f152011-10-10 10:13:09 +02004130 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004131 if (ret < 0)
4132 goto out_sleep;
4133
Eliad Pellerb67476e2011-08-14 13:17:23 +03004134 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4135 if (ret < 0)
4136 goto out_sleep;
4137
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004138 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4139 if (ret < 0)
4140 goto out_sleep;
4141
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004142out_sleep:
4143 wl1271_ps_elp_sleep(wl);
4144
Arik Nemtsov409622e2011-02-23 00:22:29 +02004145out_free_sta:
4146 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004147 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004148
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004149out:
4150 mutex_unlock(&wl->mutex);
4151 return ret;
4152}
4153
4154static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4155 struct ieee80211_vif *vif,
4156 struct ieee80211_sta *sta)
4157{
4158 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004159 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004160 struct wl1271_station *wl_sta;
4161 int ret = 0, id;
4162
4163 mutex_lock(&wl->mutex);
4164
4165 if (unlikely(wl->state == WL1271_STATE_OFF))
4166 goto out;
4167
Eliad Peller536129c2011-10-05 11:55:45 +02004168 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004169 goto out;
4170
4171 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4172
4173 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004174 id = wl_sta->hlid;
4175 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004176 goto out;
4177
Ido Yariva6208652011-03-01 15:14:41 +02004178 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004179 if (ret < 0)
4180 goto out;
4181
Eliad Pellerc690ec82011-08-14 13:17:07 +03004182 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004183 if (ret < 0)
4184 goto out_sleep;
4185
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004186 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004187
4188out_sleep:
4189 wl1271_ps_elp_sleep(wl);
4190
4191out:
4192 mutex_unlock(&wl->mutex);
4193 return ret;
4194}
4195
Luciano Coelho4623ec72011-03-21 19:26:41 +02004196static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4197 struct ieee80211_vif *vif,
4198 enum ieee80211_ampdu_mlme_action action,
4199 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4200 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004201{
4202 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004203 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004204 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004205 u8 hlid, *ba_bitmap;
4206
4207 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4208 tid);
4209
4210 /* sanity check - the fields in FW are only 8bits wide */
4211 if (WARN_ON(tid > 0xFF))
4212 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004213
4214 mutex_lock(&wl->mutex);
4215
4216 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4217 ret = -EAGAIN;
4218 goto out;
4219 }
4220
Eliad Peller536129c2011-10-05 11:55:45 +02004221 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004222 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004223 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004224 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004225 struct wl1271_station *wl_sta;
4226
4227 wl_sta = (struct wl1271_station *)sta->drv_priv;
4228 hlid = wl_sta->hlid;
4229 ba_bitmap = &wl->links[hlid].ba_bitmap;
4230 } else {
4231 ret = -EINVAL;
4232 goto out;
4233 }
4234
Ido Yariva6208652011-03-01 15:14:41 +02004235 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004236 if (ret < 0)
4237 goto out;
4238
Shahar Levi70559a02011-05-22 16:10:22 +03004239 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4240 tid, action);
4241
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004242 switch (action) {
4243 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004244 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004245 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004246 break;
4247 }
4248
4249 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4250 ret = -EBUSY;
4251 wl1271_error("exceeded max RX BA sessions");
4252 break;
4253 }
4254
4255 if (*ba_bitmap & BIT(tid)) {
4256 ret = -EINVAL;
4257 wl1271_error("cannot enable RX BA session on active "
4258 "tid: %d", tid);
4259 break;
4260 }
4261
4262 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4263 hlid);
4264 if (!ret) {
4265 *ba_bitmap |= BIT(tid);
4266 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004267 }
4268 break;
4269
4270 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004271 if (!(*ba_bitmap & BIT(tid))) {
4272 ret = -EINVAL;
4273 wl1271_error("no active RX BA session on tid: %d",
4274 tid);
4275 break;
4276 }
4277
4278 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4279 hlid);
4280 if (!ret) {
4281 *ba_bitmap &= ~BIT(tid);
4282 wl->ba_rx_session_count--;
4283 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004284 break;
4285
4286 /*
4287 * The BA initiator session management in FW independently.
4288 * Falling break here on purpose for all TX APDU commands.
4289 */
4290 case IEEE80211_AMPDU_TX_START:
4291 case IEEE80211_AMPDU_TX_STOP:
4292 case IEEE80211_AMPDU_TX_OPERATIONAL:
4293 ret = -EINVAL;
4294 break;
4295
4296 default:
4297 wl1271_error("Incorrect ampdu action id=%x\n", action);
4298 ret = -EINVAL;
4299 }
4300
4301 wl1271_ps_elp_sleep(wl);
4302
4303out:
4304 mutex_unlock(&wl->mutex);
4305
4306 return ret;
4307}
4308
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004309static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4310 struct ieee80211_vif *vif,
4311 const struct cfg80211_bitrate_mask *mask)
4312{
Eliad Peller83587502011-10-10 10:12:53 +02004313 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004314 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004315 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004316
4317 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4318 mask->control[NL80211_BAND_2GHZ].legacy,
4319 mask->control[NL80211_BAND_5GHZ].legacy);
4320
4321 mutex_lock(&wl->mutex);
4322
4323 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004324 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004325 wl1271_tx_enabled_rates_get(wl,
4326 mask->control[i].legacy,
4327 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004328
4329 if (unlikely(wl->state == WL1271_STATE_OFF))
4330 goto out;
4331
4332 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4333 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4334
4335 ret = wl1271_ps_elp_wakeup(wl);
4336 if (ret < 0)
4337 goto out;
4338
4339 wl1271_set_band_rate(wl, wlvif);
4340 wlvif->basic_rate =
4341 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4342 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4343
4344 wl1271_ps_elp_sleep(wl);
4345 }
4346out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004347 mutex_unlock(&wl->mutex);
4348
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004349 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004350}
4351
Shahar Levi6d158ff2011-09-08 13:01:33 +03004352static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4353 struct ieee80211_channel_switch *ch_switch)
4354{
4355 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004356 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004357 int ret;
4358
4359 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4360
4361 mutex_lock(&wl->mutex);
4362
4363 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004364 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4365 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4366 ieee80211_chswitch_done(vif, false);
4367 }
4368 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004369 }
4370
4371 ret = wl1271_ps_elp_wakeup(wl);
4372 if (ret < 0)
4373 goto out;
4374
Eliad Peller52630c52011-10-10 10:13:08 +02004375 /* TODO: change mac80211 to pass vif as param */
4376 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4377 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004378
Eliad Peller52630c52011-10-10 10:13:08 +02004379 if (!ret)
4380 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4381 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004382
4383 wl1271_ps_elp_sleep(wl);
4384
4385out:
4386 mutex_unlock(&wl->mutex);
4387}
4388
Arik Nemtsov33437892011-04-26 23:35:39 +03004389static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4390{
4391 struct wl1271 *wl = hw->priv;
4392 bool ret = false;
4393
4394 mutex_lock(&wl->mutex);
4395
4396 if (unlikely(wl->state == WL1271_STATE_OFF))
4397 goto out;
4398
4399 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004400 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004401out:
4402 mutex_unlock(&wl->mutex);
4403
4404 return ret;
4405}
4406
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004407/* can't be const, mac80211 writes to this */
4408static struct ieee80211_rate wl1271_rates[] = {
4409 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004410 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4411 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004412 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004413 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4414 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004415 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4416 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004417 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4418 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004419 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4420 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004421 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4422 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004423 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4424 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004425 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4426 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004427 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004428 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4429 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004430 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004431 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4432 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004433 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004434 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4435 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004436 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004437 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4438 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004439 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004440 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4441 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004442 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004443 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4444 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004445 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004446 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4447 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004448};
4449
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004450/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004451static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004452 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004453 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004454 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4455 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4456 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004457 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004458 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4459 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4460 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004461 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004462 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4463 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4464 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004465 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004466};
4467
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004468/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004469static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004470 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004471 7, /* CONF_HW_RXTX_RATE_MCS7 */
4472 6, /* CONF_HW_RXTX_RATE_MCS6 */
4473 5, /* CONF_HW_RXTX_RATE_MCS5 */
4474 4, /* CONF_HW_RXTX_RATE_MCS4 */
4475 3, /* CONF_HW_RXTX_RATE_MCS3 */
4476 2, /* CONF_HW_RXTX_RATE_MCS2 */
4477 1, /* CONF_HW_RXTX_RATE_MCS1 */
4478 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004479
4480 11, /* CONF_HW_RXTX_RATE_54 */
4481 10, /* CONF_HW_RXTX_RATE_48 */
4482 9, /* CONF_HW_RXTX_RATE_36 */
4483 8, /* CONF_HW_RXTX_RATE_24 */
4484
4485 /* TI-specific rate */
4486 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4487
4488 7, /* CONF_HW_RXTX_RATE_18 */
4489 6, /* CONF_HW_RXTX_RATE_12 */
4490 3, /* CONF_HW_RXTX_RATE_11 */
4491 5, /* CONF_HW_RXTX_RATE_9 */
4492 4, /* CONF_HW_RXTX_RATE_6 */
4493 2, /* CONF_HW_RXTX_RATE_5_5 */
4494 1, /* CONF_HW_RXTX_RATE_2 */
4495 0 /* CONF_HW_RXTX_RATE_1 */
4496};
4497
Shahar Levie8b03a22010-10-13 16:09:39 +02004498/* 11n STA capabilities */
4499#define HW_RX_HIGHEST_RATE 72
4500
Shahar Levi00d20102010-11-08 11:20:10 +00004501#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004502 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4503 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004504 .ht_supported = true, \
4505 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4506 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4507 .mcs = { \
4508 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4509 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4510 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4511 }, \
4512}
4513
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004514/* can't be const, mac80211 writes to this */
4515static struct ieee80211_supported_band wl1271_band_2ghz = {
4516 .channels = wl1271_channels,
4517 .n_channels = ARRAY_SIZE(wl1271_channels),
4518 .bitrates = wl1271_rates,
4519 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004520 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004521};
4522
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004523/* 5 GHz data rates for WL1273 */
4524static struct ieee80211_rate wl1271_rates_5ghz[] = {
4525 { .bitrate = 60,
4526 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4527 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4528 { .bitrate = 90,
4529 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4530 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4531 { .bitrate = 120,
4532 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4533 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4534 { .bitrate = 180,
4535 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4536 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4537 { .bitrate = 240,
4538 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4539 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4540 { .bitrate = 360,
4541 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4542 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4543 { .bitrate = 480,
4544 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4545 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4546 { .bitrate = 540,
4547 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4548 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4549};
4550
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004551/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004552static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004553 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4554 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4555 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4556 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4557 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4558 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4559 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4560 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4561 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4562 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4563 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4564 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4565 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4566 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4567 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4568 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4569 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4570 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4571 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4572 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4573 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4574 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4575 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4576 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4577 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4578 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4579 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4580 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4581 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4582 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4583 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4584 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4585 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4586 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004587};
4588
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004589/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004590static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004591 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004592 7, /* CONF_HW_RXTX_RATE_MCS7 */
4593 6, /* CONF_HW_RXTX_RATE_MCS6 */
4594 5, /* CONF_HW_RXTX_RATE_MCS5 */
4595 4, /* CONF_HW_RXTX_RATE_MCS4 */
4596 3, /* CONF_HW_RXTX_RATE_MCS3 */
4597 2, /* CONF_HW_RXTX_RATE_MCS2 */
4598 1, /* CONF_HW_RXTX_RATE_MCS1 */
4599 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004600
4601 7, /* CONF_HW_RXTX_RATE_54 */
4602 6, /* CONF_HW_RXTX_RATE_48 */
4603 5, /* CONF_HW_RXTX_RATE_36 */
4604 4, /* CONF_HW_RXTX_RATE_24 */
4605
4606 /* TI-specific rate */
4607 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4608
4609 3, /* CONF_HW_RXTX_RATE_18 */
4610 2, /* CONF_HW_RXTX_RATE_12 */
4611 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4612 1, /* CONF_HW_RXTX_RATE_9 */
4613 0, /* CONF_HW_RXTX_RATE_6 */
4614 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4615 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4616 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4617};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004618
4619static struct ieee80211_supported_band wl1271_band_5ghz = {
4620 .channels = wl1271_channels_5ghz,
4621 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4622 .bitrates = wl1271_rates_5ghz,
4623 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004624 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004625};
4626
Tobias Klausera0ea9492010-05-20 10:38:11 +02004627static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004628 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4629 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4630};
4631
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004632static const struct ieee80211_ops wl1271_ops = {
4633 .start = wl1271_op_start,
4634 .stop = wl1271_op_stop,
4635 .add_interface = wl1271_op_add_interface,
4636 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004637#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004638 .suspend = wl1271_op_suspend,
4639 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004640#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004641 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004642 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004643 .configure_filter = wl1271_op_configure_filter,
4644 .tx = wl1271_op_tx,
4645 .set_key = wl1271_op_set_key,
4646 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004647 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004648 .sched_scan_start = wl1271_op_sched_scan_start,
4649 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004650 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004651 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004652 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004653 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004654 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004655 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004656 .sta_add = wl1271_op_sta_add,
4657 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004658 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004659 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004660 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004661 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004662 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004663};
4664
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004665
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004666u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004667{
4668 u8 idx;
4669
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004670 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004671
4672 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4673 wl1271_error("Illegal RX rate from HW: %d", rate);
4674 return 0;
4675 }
4676
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004677 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004678 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4679 wl1271_error("Unsupported RX rate from HW: %d", rate);
4680 return 0;
4681 }
4682
4683 return idx;
4684}
4685
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004686static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4687 struct device_attribute *attr,
4688 char *buf)
4689{
4690 struct wl1271 *wl = dev_get_drvdata(dev);
4691 ssize_t len;
4692
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004693 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004694
4695 mutex_lock(&wl->mutex);
4696 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4697 wl->sg_enabled);
4698 mutex_unlock(&wl->mutex);
4699
4700 return len;
4701
4702}
4703
4704static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4705 struct device_attribute *attr,
4706 const char *buf, size_t count)
4707{
4708 struct wl1271 *wl = dev_get_drvdata(dev);
4709 unsigned long res;
4710 int ret;
4711
Luciano Coelho6277ed62011-04-01 17:49:54 +03004712 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004713 if (ret < 0) {
4714 wl1271_warning("incorrect value written to bt_coex_mode");
4715 return count;
4716 }
4717
4718 mutex_lock(&wl->mutex);
4719
4720 res = !!res;
4721
4722 if (res == wl->sg_enabled)
4723 goto out;
4724
4725 wl->sg_enabled = res;
4726
4727 if (wl->state == WL1271_STATE_OFF)
4728 goto out;
4729
Ido Yariva6208652011-03-01 15:14:41 +02004730 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004731 if (ret < 0)
4732 goto out;
4733
4734 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4735 wl1271_ps_elp_sleep(wl);
4736
4737 out:
4738 mutex_unlock(&wl->mutex);
4739 return count;
4740}
4741
4742static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4743 wl1271_sysfs_show_bt_coex_state,
4744 wl1271_sysfs_store_bt_coex_state);
4745
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004746static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4747 struct device_attribute *attr,
4748 char *buf)
4749{
4750 struct wl1271 *wl = dev_get_drvdata(dev);
4751 ssize_t len;
4752
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004753 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004754
4755 mutex_lock(&wl->mutex);
4756 if (wl->hw_pg_ver >= 0)
4757 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4758 else
4759 len = snprintf(buf, len, "n/a\n");
4760 mutex_unlock(&wl->mutex);
4761
4762 return len;
4763}
4764
Gery Kahn6f07b722011-07-18 14:21:49 +03004765static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004766 wl1271_sysfs_show_hw_pg_ver, NULL);
4767
Ido Yariv95dac04f2011-06-06 14:57:06 +03004768static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4769 struct bin_attribute *bin_attr,
4770 char *buffer, loff_t pos, size_t count)
4771{
4772 struct device *dev = container_of(kobj, struct device, kobj);
4773 struct wl1271 *wl = dev_get_drvdata(dev);
4774 ssize_t len;
4775 int ret;
4776
4777 ret = mutex_lock_interruptible(&wl->mutex);
4778 if (ret < 0)
4779 return -ERESTARTSYS;
4780
4781 /* Let only one thread read the log at a time, blocking others */
4782 while (wl->fwlog_size == 0) {
4783 DEFINE_WAIT(wait);
4784
4785 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4786 &wait,
4787 TASK_INTERRUPTIBLE);
4788
4789 if (wl->fwlog_size != 0) {
4790 finish_wait(&wl->fwlog_waitq, &wait);
4791 break;
4792 }
4793
4794 mutex_unlock(&wl->mutex);
4795
4796 schedule();
4797 finish_wait(&wl->fwlog_waitq, &wait);
4798
4799 if (signal_pending(current))
4800 return -ERESTARTSYS;
4801
4802 ret = mutex_lock_interruptible(&wl->mutex);
4803 if (ret < 0)
4804 return -ERESTARTSYS;
4805 }
4806
4807 /* Check if the fwlog is still valid */
4808 if (wl->fwlog_size < 0) {
4809 mutex_unlock(&wl->mutex);
4810 return 0;
4811 }
4812
4813 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4814 len = min(count, (size_t)wl->fwlog_size);
4815 wl->fwlog_size -= len;
4816 memcpy(buffer, wl->fwlog, len);
4817
4818 /* Make room for new messages */
4819 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4820
4821 mutex_unlock(&wl->mutex);
4822
4823 return len;
4824}
4825
4826static struct bin_attribute fwlog_attr = {
4827 .attr = {.name = "fwlog", .mode = S_IRUSR},
4828 .read = wl1271_sysfs_read_fwlog,
4829};
4830
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004831static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004832{
4833 int ret;
4834
4835 if (wl->mac80211_registered)
4836 return 0;
4837
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004838 ret = wl1271_fetch_nvs(wl);
4839 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004840 /* NOTE: The wl->nvs->nvs element must be first, in
4841 * order to simplify the casting, we assume it is at
4842 * the beginning of the wl->nvs structure.
4843 */
4844 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004845
4846 wl->mac_addr[0] = nvs_ptr[11];
4847 wl->mac_addr[1] = nvs_ptr[10];
4848 wl->mac_addr[2] = nvs_ptr[6];
4849 wl->mac_addr[3] = nvs_ptr[5];
4850 wl->mac_addr[4] = nvs_ptr[4];
4851 wl->mac_addr[5] = nvs_ptr[3];
4852 }
4853
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004854 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4855
4856 ret = ieee80211_register_hw(wl->hw);
4857 if (ret < 0) {
4858 wl1271_error("unable to register mac80211 hw: %d", ret);
4859 return ret;
4860 }
4861
4862 wl->mac80211_registered = true;
4863
Eliad Pellerd60080a2010-11-24 12:53:16 +02004864 wl1271_debugfs_init(wl);
4865
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004866 register_netdevice_notifier(&wl1271_dev_notifier);
4867
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004868 wl1271_notice("loaded");
4869
4870 return 0;
4871}
4872
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004873static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004874{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004875 if (wl->state == WL1271_STATE_PLT)
4876 __wl1271_plt_stop(wl);
4877
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004878 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004879 ieee80211_unregister_hw(wl->hw);
4880 wl->mac80211_registered = false;
4881
4882}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004883
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004884static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004885{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004886 static const u32 cipher_suites[] = {
4887 WLAN_CIPHER_SUITE_WEP40,
4888 WLAN_CIPHER_SUITE_WEP104,
4889 WLAN_CIPHER_SUITE_TKIP,
4890 WLAN_CIPHER_SUITE_CCMP,
4891 WL1271_CIPHER_SUITE_GEM,
4892 };
4893
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004894 /* The tx descriptor buffer and the TKIP space. */
4895 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4896 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004897
4898 /* unit us */
4899 /* FIXME: find a proper value */
4900 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004901 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004902
4903 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004904 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004905 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004906 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004907 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004908 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004909 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004910 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004911 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004912 IEEE80211_HW_AP_LINK_PS |
4913 IEEE80211_HW_AMPDU_AGGREGATION |
4914 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004915
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004916 wl->hw->wiphy->cipher_suites = cipher_suites;
4917 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4918
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004919 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004920 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4921 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004922 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004923 wl->hw->wiphy->max_sched_scan_ssids = 16;
4924 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004925 /*
4926 * Maximum length of elements in scanning probe request templates
4927 * should be the maximum length possible for a template, without
4928 * the IEEE80211 header of the template
4929 */
Eliad Peller154037d2011-08-14 13:17:12 +03004930 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004931 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004932
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004933 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4934 sizeof(struct ieee80211_header);
4935
Eliad Peller1ec23f72011-08-25 14:26:54 +03004936 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4937
Luciano Coelho4a31c112011-03-21 23:16:14 +02004938 /* make sure all our channels fit in the scanned_ch bitmask */
4939 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4940 ARRAY_SIZE(wl1271_channels_5ghz) >
4941 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004942 /*
4943 * We keep local copies of the band structs because we need to
4944 * modify them on a per-device basis.
4945 */
4946 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4947 sizeof(wl1271_band_2ghz));
4948 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4949 sizeof(wl1271_band_5ghz));
4950
4951 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4952 &wl->bands[IEEE80211_BAND_2GHZ];
4953 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4954 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004955
Kalle Valo12bd8942010-03-18 12:26:33 +02004956 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004957 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004958
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004959 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4960
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02004961 /* the FW answers probe-requests in AP-mode */
4962 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
4963 wl->hw->wiphy->probe_resp_offload =
4964 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
4965 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
4966 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
4967
Felipe Balbia390e852011-10-06 10:07:44 +03004968 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004969
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004970 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004971 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004972
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004973 wl->hw->max_rx_aggregation_subframes = 8;
4974
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004975 return 0;
4976}
4977
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004978#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004979
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004980static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004981{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004982 struct ieee80211_hw *hw;
4983 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004984 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004985 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004986
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004987 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004988
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004989 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4990 if (!hw) {
4991 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004992 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004993 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004994 }
4995
4996 wl = hw->priv;
4997 memset(wl, 0, sizeof(*wl));
4998
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004999 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005000 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005001
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005002 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005003
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005004 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005005 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005006 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5007
Ido Yariva6208652011-03-01 15:14:41 +02005008 skb_queue_head_init(&wl->deferred_rx_queue);
5009 skb_queue_head_init(&wl->deferred_tx_queue);
5010
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005011 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005012 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005013 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5014 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5015 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005016
Eliad Peller92ef8962011-06-07 12:50:46 +03005017 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5018 if (!wl->freezable_wq) {
5019 ret = -ENOMEM;
5020 goto err_hw;
5021 }
5022
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005023 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005024 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005025 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005026 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005027 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005028 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005029 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005030 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005031 wl->ap_ps_map = 0;
5032 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005033 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005034 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005035 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005036 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005037 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005038 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005039 wl->fwlog_size = 0;
5040 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005041
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005042 /* The system link is always allocated */
5043 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5044
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005045 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005046 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005047 wl->tx_frames[i] = NULL;
5048
5049 spin_lock_init(&wl->wl_lock);
5050
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005051 wl->state = WL1271_STATE_OFF;
5052 mutex_init(&wl->mutex);
5053
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005054 /* Apply default driver configuration. */
5055 wl1271_conf_init(wl);
5056
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005057 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5058 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5059 if (!wl->aggr_buf) {
5060 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005061 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005062 }
5063
Ido Yariv990f5de2011-03-31 10:06:59 +02005064 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5065 if (!wl->dummy_packet) {
5066 ret = -ENOMEM;
5067 goto err_aggr;
5068 }
5069
Ido Yariv95dac04f2011-06-06 14:57:06 +03005070 /* Allocate one page for the FW log */
5071 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5072 if (!wl->fwlog) {
5073 ret = -ENOMEM;
5074 goto err_dummy_packet;
5075 }
5076
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005077 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005078
Ido Yariv990f5de2011-03-31 10:06:59 +02005079err_dummy_packet:
5080 dev_kfree_skb(wl->dummy_packet);
5081
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005082err_aggr:
5083 free_pages((unsigned long)wl->aggr_buf, order);
5084
Eliad Peller92ef8962011-06-07 12:50:46 +03005085err_wq:
5086 destroy_workqueue(wl->freezable_wq);
5087
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005088err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005089 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005090 ieee80211_free_hw(hw);
5091
5092err_hw_alloc:
5093
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005094 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005095}
5096
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005097static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005098{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005099 /* Unblock any fwlog readers */
5100 mutex_lock(&wl->mutex);
5101 wl->fwlog_size = -1;
5102 wake_up_interruptible_all(&wl->fwlog_waitq);
5103 mutex_unlock(&wl->mutex);
5104
Felipe Balbif79f8902011-10-06 13:05:25 +03005105 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005106
Felipe Balbif79f8902011-10-06 13:05:25 +03005107 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005108
Felipe Balbif79f8902011-10-06 13:05:25 +03005109 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005110 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005111 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005112 free_pages((unsigned long)wl->aggr_buf,
5113 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005114
5115 wl1271_debugfs_exit(wl);
5116
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005117 vfree(wl->fw);
5118 wl->fw = NULL;
5119 kfree(wl->nvs);
5120 wl->nvs = NULL;
5121
5122 kfree(wl->fw_status);
5123 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005124 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005125
5126 ieee80211_free_hw(wl->hw);
5127
5128 return 0;
5129}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005130
Felipe Balbia390e852011-10-06 10:07:44 +03005131static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5132{
5133 struct wl1271 *wl = cookie;
5134 unsigned long flags;
5135
5136 wl1271_debug(DEBUG_IRQ, "IRQ");
5137
5138 /* complete the ELP completion */
5139 spin_lock_irqsave(&wl->wl_lock, flags);
5140 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5141 if (wl->elp_compl) {
5142 complete(wl->elp_compl);
5143 wl->elp_compl = NULL;
5144 }
5145
5146 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5147 /* don't enqueue a work right now. mark it as pending */
5148 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5149 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5150 disable_irq_nosync(wl->irq);
5151 pm_wakeup_event(wl->dev, 0);
5152 spin_unlock_irqrestore(&wl->wl_lock, flags);
5153 return IRQ_HANDLED;
5154 }
5155 spin_unlock_irqrestore(&wl->wl_lock, flags);
5156
5157 return IRQ_WAKE_THREAD;
5158}
5159
Felipe Balbice2a2172011-10-05 14:12:55 +03005160static int __devinit wl12xx_probe(struct platform_device *pdev)
5161{
Felipe Balbia390e852011-10-06 10:07:44 +03005162 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5163 struct ieee80211_hw *hw;
5164 struct wl1271 *wl;
5165 unsigned long irqflags;
5166 int ret = -ENODEV;
5167
5168 hw = wl1271_alloc_hw();
5169 if (IS_ERR(hw)) {
5170 wl1271_error("can't allocate hw");
5171 ret = PTR_ERR(hw);
5172 goto out;
5173 }
5174
5175 wl = hw->priv;
5176 wl->irq = platform_get_irq(pdev, 0);
5177 wl->ref_clock = pdata->board_ref_clock;
5178 wl->tcxo_clock = pdata->board_tcxo_clock;
5179 wl->platform_quirks = pdata->platform_quirks;
5180 wl->set_power = pdata->set_power;
5181 wl->dev = &pdev->dev;
5182 wl->if_ops = pdata->ops;
5183
5184 platform_set_drvdata(pdev, wl);
5185
5186 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5187 irqflags = IRQF_TRIGGER_RISING;
5188 else
5189 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5190
5191 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5192 irqflags,
5193 pdev->name, wl);
5194 if (ret < 0) {
5195 wl1271_error("request_irq() failed: %d", ret);
5196 goto out_free_hw;
5197 }
5198
5199 ret = enable_irq_wake(wl->irq);
5200 if (!ret) {
5201 wl->irq_wake_enabled = true;
5202 device_init_wakeup(wl->dev, 1);
5203 if (pdata->pwr_in_suspend)
5204 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5205
5206 }
5207 disable_irq(wl->irq);
5208
5209 ret = wl1271_init_ieee80211(wl);
5210 if (ret)
5211 goto out_irq;
5212
5213 ret = wl1271_register_hw(wl);
5214 if (ret)
5215 goto out_irq;
5216
Felipe Balbif79f8902011-10-06 13:05:25 +03005217 /* Create sysfs file to control bt coex state */
5218 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5219 if (ret < 0) {
5220 wl1271_error("failed to create sysfs file bt_coex_state");
5221 goto out_irq;
5222 }
5223
5224 /* Create sysfs file to get HW PG version */
5225 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5226 if (ret < 0) {
5227 wl1271_error("failed to create sysfs file hw_pg_ver");
5228 goto out_bt_coex_state;
5229 }
5230
5231 /* Create sysfs file for the FW log */
5232 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5233 if (ret < 0) {
5234 wl1271_error("failed to create sysfs file fwlog");
5235 goto out_hw_pg_ver;
5236 }
5237
Felipe Balbice2a2172011-10-05 14:12:55 +03005238 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005239
Felipe Balbif79f8902011-10-06 13:05:25 +03005240out_hw_pg_ver:
5241 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5242
5243out_bt_coex_state:
5244 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5245
Felipe Balbia390e852011-10-06 10:07:44 +03005246out_irq:
5247 free_irq(wl->irq, wl);
5248
5249out_free_hw:
5250 wl1271_free_hw(wl);
5251
5252out:
5253 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005254}
5255
5256static int __devexit wl12xx_remove(struct platform_device *pdev)
5257{
Felipe Balbia390e852011-10-06 10:07:44 +03005258 struct wl1271 *wl = platform_get_drvdata(pdev);
5259
5260 if (wl->irq_wake_enabled) {
5261 device_init_wakeup(wl->dev, 0);
5262 disable_irq_wake(wl->irq);
5263 }
5264 wl1271_unregister_hw(wl);
5265 free_irq(wl->irq, wl);
5266 wl1271_free_hw(wl);
5267
Felipe Balbice2a2172011-10-05 14:12:55 +03005268 return 0;
5269}
5270
5271static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005272 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005273 { } /* Terminating Entry */
5274};
5275MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5276
5277static struct platform_driver wl12xx_driver = {
5278 .probe = wl12xx_probe,
5279 .remove = __devexit_p(wl12xx_remove),
5280 .id_table = wl12xx_id_table,
5281 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005282 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005283 .owner = THIS_MODULE,
5284 }
5285};
5286
5287static int __init wl12xx_init(void)
5288{
5289 return platform_driver_register(&wl12xx_driver);
5290}
5291module_init(wl12xx_init);
5292
5293static void __exit wl12xx_exit(void)
5294{
5295 platform_driver_unregister(&wl12xx_driver);
5296}
5297module_exit(wl12xx_exit);
5298
Guy Eilam491bbd62011-01-12 10:33:29 +01005299u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005300EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005301module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005302MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5303
Ido Yariv95dac04f2011-06-06 14:57:06 +03005304module_param_named(fwlog, fwlog_param, charp, 0);
5305MODULE_PARM_DESC(keymap,
5306 "FW logger options: continuous, ondemand, dbgpins or disable");
5307
Eliad Peller2a5bff02011-08-25 18:10:59 +03005308module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5309MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5310
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005311MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005312MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005313MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");