blob: 74d4abb25ab118261a50ef4eceb41002a97526e9 [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,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300238 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200239 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300240 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300241 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200242 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300243 .keep_alive_interval = 55000,
244 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300245 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200246 .itrim = {
247 .enable = false,
248 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200249 },
250 .pm_config = {
251 .host_clk_settling_time = 5000,
252 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300253 },
254 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300255 .trigger_pacing = 1,
256 .avg_weight_rssi_beacon = 20,
257 .avg_weight_rssi_data = 10,
258 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100259 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200260 },
261 .scan = {
262 .min_dwell_time_active = 7500,
263 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100264 .min_dwell_time_passive = 100000,
265 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200266 .num_probe_reqs = 2,
267 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300268 .sched_scan = {
269 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300270 .min_dwell_time_active = 30,
271 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300272 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300273 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300274 .num_probe_reqs = 2,
275 .rssi_threshold = -90,
276 .snr_threshold = 0,
277 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200278 .rf = {
279 .tx_per_channel_power_compensation_2 = {
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
281 },
282 .tx_per_channel_power_compensation_5 = {
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 },
287 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100288 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300289 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100290 .tx_ba_win_size = 64,
291 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300292 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100293 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200294 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200295 .num_stations = 1,
296 .ssid_profiles = 1,
297 .rx_block_num = 70,
298 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300299 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200300 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200301 .min_req_rx_blocks = 22,
302 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200303 },
304 .mem_wl128x = {
305 .num_stations = 1,
306 .ssid_profiles = 1,
307 .rx_block_num = 40,
308 .tx_min_block_num = 40,
309 .dynamic_memory = 1,
310 .min_req_tx_blocks = 45,
311 .min_req_rx_blocks = 22,
312 .tx_min = 27,
313 },
Shahar Leviff868432011-04-11 15:41:46 +0300314 .fm_coex = {
315 .enable = true,
316 .swallow_period = 5,
317 .n_divider_fref_set_1 = 0xff, /* default */
318 .n_divider_fref_set_2 = 12,
319 .m_divider_fref_set_1 = 148,
320 .m_divider_fref_set_2 = 0xffff, /* default */
321 .coex_pll_stabilization_time = 0xffffffff, /* default */
322 .ldo_stabilization_time = 0xffff, /* default */
323 .fm_disturbed_band_margin = 0xff, /* default */
324 .swallow_clk_diff = 0xff, /* default */
325 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300326 .rx_streaming = {
327 .duration = 150,
328 .queues = 0x1,
329 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300330 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300331 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300332 .fwlog = {
333 .mode = WL12XX_FWLOG_ON_DEMAND,
334 .mem_blocks = 2,
335 .severity = 0,
336 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
337 .output = WL12XX_FWLOG_OUTPUT_HOST,
338 .threshold = 0,
339 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300340 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300341 .rate = {
342 .rate_retry_score = 32000,
343 .per_add = 8192,
344 .per_th1 = 2048,
345 .per_th2 = 4096,
346 .max_per = 8100,
347 .inverse_curiosity_factor = 5,
348 .tx_fail_low_th = 4,
349 .tx_fail_high_th = 10,
350 .per_alpha_shift = 4,
351 .per_add_shift = 13,
352 .per_beta1_shift = 10,
353 .per_beta2_shift = 8,
354 .rate_check_up = 2,
355 .rate_check_down = 12,
356 .rate_retry_policy = {
357 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00,
360 },
361 },
Eliad Peller94877752011-08-28 15:11:56 +0300362 .hangover = {
363 .recover_time = 0,
364 .hangover_period = 20,
365 .dynamic_mode = 1,
366 .early_termination_mode = 1,
367 .max_period = 20,
368 .min_period = 1,
369 .increase_delta = 1,
370 .decrease_delta = 2,
371 .quiet_time = 4,
372 .increase_time = 1,
373 .window_size = 16,
374 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300375};
376
Ido Yariv95dac04f2011-06-06 14:57:06 +0300377static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300378static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300379
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300380static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200381 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300382 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200383static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200384static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200385
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200386static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300387static LIST_HEAD(wl_list);
388
Eliad Pellerba8447f2011-10-10 10:13:00 +0200389static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
390 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300391{
392 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200393
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300394 if (operstate != IF_OPER_UP)
395 return 0;
396
Eliad Peller8181aec2011-10-10 10:13:04 +0200397 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300398 return 0;
399
Eliad Peller154da672011-10-05 11:55:53 +0200400 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300401 if (ret < 0)
402 return ret;
403
Eliad Peller0603d892011-10-05 11:55:51 +0200404 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300405
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300406 wl1271_info("Association completed.");
407 return 0;
408}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300409static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
410 void *arg)
411{
412 struct net_device *dev = arg;
413 struct wireless_dev *wdev;
414 struct wiphy *wiphy;
415 struct ieee80211_hw *hw;
416 struct wl1271 *wl;
417 struct wl1271 *wl_temp;
Eliad Pellerba8447f2011-10-10 10:13:00 +0200418 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300419 int ret = 0;
420
421 /* Check that this notification is for us. */
422 if (what != NETDEV_CHANGE)
423 return NOTIFY_DONE;
424
425 wdev = dev->ieee80211_ptr;
426 if (wdev == NULL)
427 return NOTIFY_DONE;
428
429 wiphy = wdev->wiphy;
430 if (wiphy == NULL)
431 return NOTIFY_DONE;
432
433 hw = wiphy_priv(wiphy);
434 if (hw == NULL)
435 return NOTIFY_DONE;
436
437 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200438 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300439 list_for_each_entry(wl, &wl_list, list) {
440 if (wl == wl_temp)
441 break;
442 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200443 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300444 if (wl != wl_temp)
445 return NOTIFY_DONE;
446
447 mutex_lock(&wl->mutex);
448
449 if (wl->state == WL1271_STATE_OFF)
450 goto out;
451
Eliad Peller6ab70912011-12-18 20:25:45 +0200452 if (dev->operstate != IF_OPER_UP)
453 goto out;
454 /*
455 * The correct behavior should be just getting the appropriate wlvif
456 * from the given dev, but currently we don't have a mac80211
457 * interface for it.
458 */
Eliad Pellerba8447f2011-10-10 10:13:00 +0200459 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller6ab70912011-12-18 20:25:45 +0200460 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
461
Eliad Pellerba8447f2011-10-10 10:13:00 +0200462 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
463 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300464
Eliad Pellerba8447f2011-10-10 10:13:00 +0200465 ret = wl1271_ps_elp_wakeup(wl);
466 if (ret < 0)
467 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300468
Eliad Peller6ab70912011-12-18 20:25:45 +0200469 wl1271_check_operstate(wl, wlvif,
470 ieee80211_get_operstate(vif));
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300471
Eliad Pellerba8447f2011-10-10 10:13:00 +0200472 wl1271_ps_elp_sleep(wl);
473 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300474out:
475 mutex_unlock(&wl->mutex);
476
477 return NOTIFY_OK;
478}
479
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100480static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200481 struct regulatory_request *request)
482{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100483 struct ieee80211_supported_band *band;
484 struct ieee80211_channel *ch;
485 int i;
486
487 band = wiphy->bands[IEEE80211_BAND_5GHZ];
488 for (i = 0; i < band->n_channels; i++) {
489 ch = &band->channels[i];
490 if (ch->flags & IEEE80211_CHAN_DISABLED)
491 continue;
492
493 if (ch->flags & IEEE80211_CHAN_RADAR)
494 ch->flags |= IEEE80211_CHAN_NO_IBSS |
495 IEEE80211_CHAN_PASSIVE_SCAN;
496
497 }
498
499 return 0;
500}
501
Eliad Peller9eb599e2011-10-10 10:12:59 +0200502static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
503 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300504{
505 int ret = 0;
506
507 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200508 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300509 if (ret < 0)
510 goto out;
511
512 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200513 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300514 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200515 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300516out:
517 return ret;
518}
519
520/*
521 * this function is being called when the rx_streaming interval
522 * has beed changed or rx_streaming should be disabled
523 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200524int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300525{
526 int ret = 0;
527 int period = wl->conf.rx_streaming.interval;
528
529 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200530 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300531 goto out;
532
533 /* reconfigure/disable according to new streaming_period */
534 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200535 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300536 (wl->conf.rx_streaming.always ||
537 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200538 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300539 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200540 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300541 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200542 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300543 }
544out:
545 return ret;
546}
547
548static void wl1271_rx_streaming_enable_work(struct work_struct *work)
549{
550 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200551 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
552 rx_streaming_enable_work);
553 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300554
555 mutex_lock(&wl->mutex);
556
Eliad Peller0744bdb2011-10-10 10:13:05 +0200557 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200558 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300559 (!wl->conf.rx_streaming.always &&
560 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
561 goto out;
562
563 if (!wl->conf.rx_streaming.interval)
564 goto out;
565
566 ret = wl1271_ps_elp_wakeup(wl);
567 if (ret < 0)
568 goto out;
569
Eliad Peller9eb599e2011-10-10 10:12:59 +0200570 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300571 if (ret < 0)
572 goto out_sleep;
573
574 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200575 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300576 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
577
578out_sleep:
579 wl1271_ps_elp_sleep(wl);
580out:
581 mutex_unlock(&wl->mutex);
582}
583
584static void wl1271_rx_streaming_disable_work(struct work_struct *work)
585{
586 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200587 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
588 rx_streaming_disable_work);
589 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300590
591 mutex_lock(&wl->mutex);
592
Eliad Peller0744bdb2011-10-10 10:13:05 +0200593 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300594 goto out;
595
596 ret = wl1271_ps_elp_wakeup(wl);
597 if (ret < 0)
598 goto out;
599
Eliad Peller9eb599e2011-10-10 10:12:59 +0200600 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300601 if (ret)
602 goto out_sleep;
603
604out_sleep:
605 wl1271_ps_elp_sleep(wl);
606out:
607 mutex_unlock(&wl->mutex);
608}
609
610static void wl1271_rx_streaming_timer(unsigned long data)
611{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200612 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
613 struct wl1271 *wl = wlvif->wl;
614 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300615}
616
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300617static void wl1271_conf_init(struct wl1271 *wl)
618{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300619
620 /*
621 * This function applies the default configuration to the driver. This
622 * function is invoked upon driver load (spi probe.)
623 *
624 * The configuration is stored in a run-time structure in order to
625 * facilitate for run-time adjustment of any of the parameters. Making
626 * changes to the configuration structure will apply the new values on
627 * the next interface up (wl1271_op_start.)
628 */
629
630 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300631 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300632
Ido Yariv95dac04f2011-06-06 14:57:06 +0300633 /* Adjust settings according to optional module parameters */
634 if (fwlog_param) {
635 if (!strcmp(fwlog_param, "continuous")) {
636 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
637 } else if (!strcmp(fwlog_param, "ondemand")) {
638 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
639 } else if (!strcmp(fwlog_param, "dbgpins")) {
640 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
641 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
642 } else if (!strcmp(fwlog_param, "disable")) {
643 wl->conf.fwlog.mem_blocks = 0;
644 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
645 } else {
646 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
647 }
648 }
649}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300650
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651static int wl1271_plt_init(struct wl1271 *wl)
652{
Eliad Peller188e7f52011-12-06 12:15:06 +0200653 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300654
Shahar Levi49d750ca2011-03-06 16:32:09 +0200655 if (wl->chip.id == CHIP_ID_1283_PG20)
656 ret = wl128x_cmd_general_parms(wl);
657 else
658 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200659 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200660 return ret;
661
Shahar Levi49d750ca2011-03-06 16:32:09 +0200662 if (wl->chip.id == CHIP_ID_1283_PG20)
663 ret = wl128x_cmd_radio_parms(wl);
664 else
665 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200666 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200667 return ret;
668
Shahar Levi49d750ca2011-03-06 16:32:09 +0200669 if (wl->chip.id != CHIP_ID_1283_PG20) {
670 ret = wl1271_cmd_ext_radio_parms(wl);
671 if (ret < 0)
672 return ret;
673 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200674 if (ret < 0)
675 return ret;
676
Shahar Levi48a61472011-03-06 16:32:08 +0200677 /* Chip-specific initializations */
678 ret = wl1271_chip_specific_init(wl);
679 if (ret < 0)
680 return ret;
681
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300682 ret = wl1271_acx_init_mem_config(wl);
683 if (ret < 0)
684 return ret;
685
Eliad Peller7f0979882011-08-14 13:17:06 +0300686 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600687 if (ret < 0)
688 goto out_free_memmap;
689
Luciano Coelho12419cc2010-02-18 13:25:44 +0200690 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200691 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300692 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200693 goto out_free_memmap;
694
695 /* Configure for CAM power saving (ie. always active) */
696 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
697 if (ret < 0)
698 goto out_free_memmap;
699
700 /* configure PM */
701 ret = wl1271_acx_pm_config(wl);
702 if (ret < 0)
703 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300704
705 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200706
707 out_free_memmap:
708 kfree(wl->target_mem_map);
709 wl->target_mem_map = NULL;
710
711 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712}
713
Eliad Peller6e8cd332011-10-10 10:13:13 +0200714static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
715 struct wl12xx_vif *wlvif,
716 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200717{
Arik Nemtsovda032092011-08-25 12:43:15 +0300718 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200719
Arik Nemtsovb622d992011-02-23 00:22:31 +0200720 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300721 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200722
723 /*
724 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300725 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200726 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300727 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200728 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200729
Arik Nemtsovda032092011-08-25 12:43:15 +0300730 /*
731 * Start high-level PS if the STA is asleep with enough blocks in FW.
732 * Make an exception if this is the only connected station. In this
733 * case FW-memory congestion is not a problem.
734 */
735 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200736 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200737}
738
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300739static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200740 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300741 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200742{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200743 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200744 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300745 u8 hlid, cnt;
746
747 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200748
749 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
750 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
751 wl1271_debug(DEBUG_PSM,
752 "link ps prev 0x%x cur 0x%x changed 0x%x",
753 wl->ap_fw_ps_map, cur_fw_ps_map,
754 wl->ap_fw_ps_map ^ cur_fw_ps_map);
755
756 wl->ap_fw_ps_map = cur_fw_ps_map;
757 }
758
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200759 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
760 lnk = &wl->links[hlid];
761 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200762
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200763 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
764 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200765
Eliad Peller6e8cd332011-10-10 10:13:13 +0200766 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
767 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200768 }
769}
770
Eliad Peller4d56ad92011-08-14 13:17:05 +0300771static void wl12xx_fw_status(struct wl1271 *wl,
772 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300773{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200774 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200775 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200776 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300777 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300778 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300779
Eliad Peller4d56ad92011-08-14 13:17:05 +0300780 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200781
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300782 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
783 "drv_rx_counter = %d, tx_results_counter = %d)",
784 status->intr,
785 status->fw_rx_counter,
786 status->drv_rx_counter,
787 status->tx_results_counter);
788
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300789 for (i = 0; i < NUM_TX_QUEUES; i++) {
790 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300791 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300792 (status->tx_released_pkts[i] -
793 wl->tx_pkts_freed[i]) & 0xff;
794
795 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
796 }
797
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300798 /* prevent wrap-around in total blocks counter */
799 if (likely(wl->tx_blocks_freed <=
800 le32_to_cpu(status->total_released_blks)))
801 freed_blocks = le32_to_cpu(status->total_released_blks) -
802 wl->tx_blocks_freed;
803 else
804 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
805 le32_to_cpu(status->total_released_blks);
806
Eliad Peller4d56ad92011-08-14 13:17:05 +0300807 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200808
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300809 wl->tx_allocated_blocks -= freed_blocks;
810
Eliad Peller4d56ad92011-08-14 13:17:05 +0300811 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200812
Eliad Peller4d56ad92011-08-14 13:17:05 +0300813 /*
814 * The FW might change the total number of TX memblocks before
815 * we get a notification about blocks being released. Thus, the
816 * available blocks calculation might yield a temporary result
817 * which is lower than the actual available blocks. Keeping in
818 * mind that only blocks that were allocated can be moved from
819 * TX to RX, tx_blocks_available should never decrease here.
820 */
821 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
822 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300823
Ido Yariva5225502010-10-12 14:49:10 +0200824 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200825 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200826 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300827
Eliad Peller4d56ad92011-08-14 13:17:05 +0300828 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200829 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200830 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200831 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300832
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300833 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200834 getnstimeofday(&ts);
835 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
836 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300837}
838
Ido Yariva6208652011-03-01 15:14:41 +0200839static void wl1271_flush_deferred_work(struct wl1271 *wl)
840{
841 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200842
Ido Yariva6208652011-03-01 15:14:41 +0200843 /* Pass all received frames to the network stack */
844 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
845 ieee80211_rx_ni(wl->hw, skb);
846
847 /* Return sent skbs to the network stack */
848 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300849 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200850}
851
852static void wl1271_netstack_work(struct work_struct *work)
853{
854 struct wl1271 *wl =
855 container_of(work, struct wl1271, netstack_work);
856
857 do {
858 wl1271_flush_deferred_work(wl);
859 } while (skb_queue_len(&wl->deferred_rx_queue));
860}
861
862#define WL1271_IRQ_MAX_LOOPS 256
863
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300864static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300865{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300866 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300867 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200868 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200869 struct wl1271 *wl = (struct wl1271 *)cookie;
870 bool done = false;
871 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200872 unsigned long flags;
873
874 /* TX might be handled here, avoid redundant work */
875 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
876 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300877
Ido Yariv341b7cd2011-03-31 10:07:01 +0200878 /*
879 * In case edge triggered interrupt must be used, we cannot iterate
880 * more than once without introducing race conditions with the hardirq.
881 */
882 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
883 loopcount = 1;
884
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300885 mutex_lock(&wl->mutex);
886
887 wl1271_debug(DEBUG_IRQ, "IRQ work");
888
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200889 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300890 goto out;
891
Ido Yariva6208652011-03-01 15:14:41 +0200892 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300893 if (ret < 0)
894 goto out;
895
Ido Yariva6208652011-03-01 15:14:41 +0200896 while (!done && loopcount--) {
897 /*
898 * In order to avoid a race with the hardirq, clear the flag
899 * before acknowledging the chip. Since the mutex is held,
900 * wl1271_ps_elp_wakeup cannot be called concurrently.
901 */
902 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
903 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200904
Eliad Peller4d56ad92011-08-14 13:17:05 +0300905 wl12xx_fw_status(wl, wl->fw_status);
906 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200907 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200908 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200909 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200910 continue;
911 }
912
Eliad Pellerccc83b02010-10-27 14:09:57 +0200913 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
914 wl1271_error("watchdog interrupt received! "
915 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300916 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200917
918 /* restarting the chip. ignore any other interrupt. */
919 goto out;
920 }
921
Ido Yariva6208652011-03-01 15:14:41 +0200922 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200923 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
924
Eliad Peller4d56ad92011-08-14 13:17:05 +0300925 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200926
Ido Yariva5225502010-10-12 14:49:10 +0200927 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200928 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200929 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300930 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200931 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200932 /*
933 * In order to avoid starvation of the TX path,
934 * call the work function directly.
935 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200936 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200937 } else {
938 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200939 }
940
Ido Yariv8aad2462011-03-01 15:14:38 +0200941 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300942 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200943 (wl->tx_results_count & 0xff))
944 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200945
946 /* Make sure the deferred queues don't get too long */
947 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
948 skb_queue_len(&wl->deferred_rx_queue);
949 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
950 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200951 }
952
953 if (intr & WL1271_ACX_INTR_EVENT_A) {
954 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
955 wl1271_event_handle(wl, 0);
956 }
957
958 if (intr & WL1271_ACX_INTR_EVENT_B) {
959 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
960 wl1271_event_handle(wl, 1);
961 }
962
963 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
964 wl1271_debug(DEBUG_IRQ,
965 "WL1271_ACX_INTR_INIT_COMPLETE");
966
967 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
968 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300969 }
970
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300971 wl1271_ps_elp_sleep(wl);
972
973out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200974 spin_lock_irqsave(&wl->wl_lock, flags);
975 /* In case TX was not handled here, queue TX work */
976 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
977 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300978 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200979 ieee80211_queue_work(wl->hw, &wl->tx_work);
980 spin_unlock_irqrestore(&wl->wl_lock, flags);
981
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300982 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200983
984 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300985}
986
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300987static int wl1271_fetch_firmware(struct wl1271 *wl)
988{
989 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200990 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991 int ret;
992
Arik Nemtsovc302b2c2011-08-17 10:45:48 +0300993 if (wl->chip.id == CHIP_ID_1283_PG20)
994 fw_name = WL128X_FW_NAME;
995 else
996 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200997
998 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
999
Felipe Balbia390e852011-10-06 10:07:44 +03001000 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001001
1002 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001003 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001004 return ret;
1005 }
1006
1007 if (fw->size % 4) {
1008 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1009 fw->size);
1010 ret = -EILSEQ;
1011 goto out;
1012 }
1013
Arik Nemtsov166d5042010-10-16 21:44:57 +02001014 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001015 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001016 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001017
1018 if (!wl->fw) {
1019 wl1271_error("could not allocate memory for the firmware");
1020 ret = -ENOMEM;
1021 goto out;
1022 }
1023
1024 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025 ret = 0;
1026
1027out:
1028 release_firmware(fw);
1029
1030 return ret;
1031}
1032
1033static int wl1271_fetch_nvs(struct wl1271 *wl)
1034{
1035 const struct firmware *fw;
1036 int ret;
1037
Felipe Balbia390e852011-10-06 10:07:44 +03001038 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039
1040 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001041 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
1042 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043 return ret;
1044 }
1045
Shahar Levibc765bf2011-03-06 16:32:10 +02001046 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047
1048 if (!wl->nvs) {
1049 wl1271_error("could not allocate memory for the nvs file");
1050 ret = -ENOMEM;
1051 goto out;
1052 }
1053
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001054 wl->nvs_len = fw->size;
1055
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056out:
1057 release_firmware(fw);
1058
1059 return ret;
1060}
1061
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001062void wl12xx_queue_recovery_work(struct wl1271 *wl)
1063{
1064 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1065 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1066}
1067
Ido Yariv95dac04f2011-06-06 14:57:06 +03001068size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1069{
1070 size_t len = 0;
1071
1072 /* The FW log is a length-value list, find where the log end */
1073 while (len < maxlen) {
1074 if (memblock[len] == 0)
1075 break;
1076 if (len + memblock[len] + 1 > maxlen)
1077 break;
1078 len += memblock[len] + 1;
1079 }
1080
1081 /* Make sure we have enough room */
1082 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1083
1084 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1085 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1086 wl->fwlog_size += len;
1087
1088 return len;
1089}
1090
1091static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1092{
1093 u32 addr;
1094 u32 first_addr;
1095 u8 *block;
1096
1097 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1098 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1099 (wl->conf.fwlog.mem_blocks == 0))
1100 return;
1101
1102 wl1271_info("Reading FW panic log");
1103
1104 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1105 if (!block)
1106 return;
1107
1108 /*
1109 * Make sure the chip is awake and the logger isn't active.
1110 * This might fail if the firmware hanged.
1111 */
1112 if (!wl1271_ps_elp_wakeup(wl))
1113 wl12xx_cmd_stop_fwlog(wl);
1114
1115 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001116 wl12xx_fw_status(wl, wl->fw_status);
1117 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001118 if (!first_addr)
1119 goto out;
1120
1121 /* Traverse the memory blocks linked list */
1122 addr = first_addr;
1123 do {
1124 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1125 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1126 false);
1127
1128 /*
1129 * Memory blocks are linked to one another. The first 4 bytes
1130 * of each memory block hold the hardware address of the next
1131 * one. The last memory block points to the first one.
1132 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001133 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001134 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1135 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1136 break;
1137 } while (addr && (addr != first_addr));
1138
1139 wake_up_interruptible(&wl->fwlog_waitq);
1140
1141out:
1142 kfree(block);
1143}
1144
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001145static void wl1271_recovery_work(struct work_struct *work)
1146{
1147 struct wl1271 *wl =
1148 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001149 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001150 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001151
1152 mutex_lock(&wl->mutex);
1153
1154 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001155 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001156
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001157 /* Avoid a recursive recovery */
1158 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1159
Ido Yariv95dac04f2011-06-06 14:57:06 +03001160 wl12xx_read_fwlog_panic(wl);
1161
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001162 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1163 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001164
Eliad Peller2a5bff02011-08-25 18:10:59 +03001165 BUG_ON(bug_on_recovery);
1166
Oz Krakowskib992c682011-06-26 10:36:02 +03001167 /*
1168 * Advance security sequence number to overcome potential progress
1169 * in the firmware during recovery. This doens't hurt if the network is
1170 * not encrypted.
1171 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001172 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001173 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001174 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001175 wlvif->tx_security_seq +=
1176 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1177 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001178
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001179 /* Prevent spurious TX during FW restart */
1180 ieee80211_stop_queues(wl->hw);
1181
Luciano Coelho33c2c062011-05-10 14:46:02 +03001182 if (wl->sched_scanning) {
1183 ieee80211_sched_scan_stopped(wl->hw);
1184 wl->sched_scanning = false;
1185 }
1186
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001187 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001188 while (!list_empty(&wl->wlvif_list)) {
1189 wlvif = list_first_entry(&wl->wlvif_list,
1190 struct wl12xx_vif, list);
1191 vif = wl12xx_wlvif_to_vif(wlvif);
1192 __wl1271_op_remove_interface(wl, vif, false);
1193 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001194 mutex_unlock(&wl->mutex);
1195 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001196
1197 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1198
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001199 ieee80211_restart_hw(wl->hw);
1200
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001201 /*
1202 * Its safe to enable TX now - the queues are stopped after a request
1203 * to restart the HW.
1204 */
1205 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001206 return;
1207out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001208 mutex_unlock(&wl->mutex);
1209}
1210
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001211static void wl1271_fw_wakeup(struct wl1271 *wl)
1212{
1213 u32 elp_reg;
1214
1215 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001216 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001217}
1218
1219static int wl1271_setup(struct wl1271 *wl)
1220{
1221 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1222 if (!wl->fw_status)
1223 return -ENOMEM;
1224
1225 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1226 if (!wl->tx_res_if) {
1227 kfree(wl->fw_status);
1228 return -ENOMEM;
1229 }
1230
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001231 return 0;
1232}
1233
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001234static int wl12xx_set_power_on(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001235{
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001236 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001237
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001238 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001239 ret = wl1271_power_on(wl);
1240 if (ret < 0)
1241 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001242 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001243 wl1271_io_reset(wl);
1244 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001245
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001246 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247
1248 /* ELP module wake up */
1249 wl1271_fw_wakeup(wl);
1250
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001251out:
1252 return ret;
1253}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001255static int wl1271_chip_wakeup(struct wl1271 *wl)
1256{
1257 int ret = 0;
1258
1259 ret = wl12xx_set_power_on(wl);
1260 if (ret < 0)
1261 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001262
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001263 /*
1264 * For wl127x based devices we could use the default block
1265 * size (512 bytes), but due to a bug in the sdio driver, we
1266 * need to set it explicitly after the chip is powered on. To
1267 * simplify the code and since the performance impact is
1268 * negligible, we use the same block size for all different
1269 * chip types.
1270 */
1271 if (!wl1271_set_block_size(wl))
1272 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273
1274 switch (wl->chip.id) {
1275 case CHIP_ID_1271_PG10:
1276 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1277 wl->chip.id);
1278
1279 ret = wl1271_setup(wl);
1280 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001281 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001282 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001284
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 case CHIP_ID_1271_PG20:
1286 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1287 wl->chip.id);
1288
1289 ret = wl1271_setup(wl);
1290 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001291 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001292 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001293 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001294
Shahar Levi0830cee2011-03-06 16:32:20 +02001295 case CHIP_ID_1283_PG20:
1296 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1297 wl->chip.id);
1298
1299 ret = wl1271_setup(wl);
1300 if (ret < 0)
1301 goto out;
1302 break;
1303 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001304 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001305 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001307 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001308 }
1309
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001310 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001311 ret = wl1271_fetch_firmware(wl);
1312 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001313 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314 }
1315
1316 /* No NVS from netlink, try to get it from the filesystem */
1317 if (wl->nvs == NULL) {
1318 ret = wl1271_fetch_nvs(wl);
1319 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001320 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321 }
1322
1323out:
1324 return ret;
1325}
1326
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327int wl1271_plt_start(struct wl1271 *wl)
1328{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001329 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001330 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331 int ret;
1332
1333 mutex_lock(&wl->mutex);
1334
1335 wl1271_notice("power up");
1336
1337 if (wl->state != WL1271_STATE_OFF) {
1338 wl1271_error("cannot go into PLT state because not "
1339 "in off state: %d", wl->state);
1340 ret = -EBUSY;
1341 goto out;
1342 }
1343
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001344 while (retries) {
1345 retries--;
1346 ret = wl1271_chip_wakeup(wl);
1347 if (ret < 0)
1348 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001349
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001350 ret = wl1271_boot(wl);
1351 if (ret < 0)
1352 goto power_off;
1353
1354 ret = wl1271_plt_init(wl);
1355 if (ret < 0)
1356 goto irq_disable;
1357
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001358 wl->state = WL1271_STATE_PLT;
1359 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001360 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001361
Gery Kahn6f07b722011-07-18 14:21:49 +03001362 /* update hw/fw version info in wiphy struct */
1363 wiphy->hw_version = wl->chip.id;
1364 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1365 sizeof(wiphy->fw_version));
1366
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367 goto out;
1368
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001369irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001370 mutex_unlock(&wl->mutex);
1371 /* Unlocking the mutex in the middle of handling is
1372 inherently unsafe. In this case we deem it safe to do,
1373 because we need to let any possibly pending IRQ out of
1374 the system (and while we are WL1271_STATE_OFF the IRQ
1375 work function will not do anything.) Also, any other
1376 possible concurrent operations will fail due to the
1377 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001378 wl1271_disable_interrupts(wl);
1379 wl1271_flush_deferred_work(wl);
1380 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001381 mutex_lock(&wl->mutex);
1382power_off:
1383 wl1271_power_off(wl);
1384 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001386 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1387 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001388out:
1389 mutex_unlock(&wl->mutex);
1390
1391 return ret;
1392}
1393
Ido Yarivf3df1332012-01-11 09:42:39 +02001394int wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001395{
1396 int ret = 0;
1397
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001398 wl1271_notice("power down");
1399
Ido Yariv46b0cc92012-01-11 09:42:41 +02001400 /*
1401 * Interrupts must be disabled before setting the state to OFF.
1402 * Otherwise, the interrupt handler might be called and exit without
1403 * reading the interrupt status.
1404 */
1405 wl1271_disable_interrupts(wl);
Ido Yarivf3df1332012-01-11 09:42:39 +02001406 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407 if (wl->state != WL1271_STATE_PLT) {
Ido Yarivf3df1332012-01-11 09:42:39 +02001408 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001409
1410 /*
1411 * This will not necessarily enable interrupts as interrupts
1412 * may have been disabled when op_stop was called. It will,
1413 * however, balance the above call to disable_interrupts().
1414 */
1415 wl1271_enable_interrupts(wl);
1416
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001417 wl1271_error("cannot power down because not in PLT "
1418 "state: %d", wl->state);
1419 ret = -EBUSY;
1420 goto out;
1421 }
1422
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001423 mutex_unlock(&wl->mutex);
Ido Yarivf3df1332012-01-11 09:42:39 +02001424
Ido Yariva6208652011-03-01 15:14:41 +02001425 wl1271_flush_deferred_work(wl);
1426 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001427 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001428 cancel_delayed_work_sync(&wl->elp_work);
Ido Yariva4549692012-01-11 09:42:40 +02001429
1430 mutex_lock(&wl->mutex);
1431 wl1271_power_off(wl);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001432 wl->flags = 0;
1433 wl->state = WL1271_STATE_OFF;
1434 wl->rx_counter = 0;
Ido Yariva4549692012-01-11 09:42:40 +02001435 mutex_unlock(&wl->mutex);
1436
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001437out:
1438 return ret;
1439}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001440
Johannes Berg7bb45682011-02-24 14:42:06 +01001441static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001442{
1443 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001444 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1445 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001446 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001447 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001448 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001449 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001450
Eliad Peller0f168012011-10-11 13:52:25 +02001451 if (vif)
1452 wlvif = wl12xx_vif_to_data(vif);
1453
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001454 mapping = skb_get_queue_mapping(skb);
1455 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001456
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001457 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001458
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001459 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001460
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001461 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001462 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001463 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001464 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001465 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001466 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001467 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001468
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001469 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1470 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1471
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001472 wl->tx_queue_count[q]++;
1473
1474 /*
1475 * The workqueue is slow to process the tx_queue and we need stop
1476 * the queue here, otherwise the queue will get too long.
1477 */
1478 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1479 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1480 ieee80211_stop_queue(wl->hw, mapping);
1481 set_bit(q, &wl->stopped_queues_map);
1482 }
1483
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001484 /*
1485 * The chip specific setup must run before the first TX packet -
1486 * before that, the tx_work will not be initialized!
1487 */
1488
Ido Yarivb07d4032011-03-01 15:14:43 +02001489 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1490 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001491 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001492
Arik Nemtsov04216da2011-08-14 13:17:38 +03001493out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001494 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001495}
1496
Shahar Leviae47c452011-03-06 16:32:14 +02001497int wl1271_tx_dummy_packet(struct wl1271 *wl)
1498{
Ido Yariv990f5de2011-03-31 10:06:59 +02001499 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001500 int q;
1501
1502 /* no need to queue a new dummy packet if one is already pending */
1503 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1504 return 0;
1505
1506 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001507
Ido Yariv990f5de2011-03-31 10:06:59 +02001508 spin_lock_irqsave(&wl->wl_lock, flags);
1509 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001510 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001511 spin_unlock_irqrestore(&wl->wl_lock, flags);
1512
1513 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1514 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001515 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001516
1517 /*
1518 * If the FW TX is busy, TX work will be scheduled by the threaded
1519 * interrupt handler function
1520 */
1521 return 0;
1522}
1523
1524/*
1525 * The size of the dummy packet should be at least 1400 bytes. However, in
1526 * order to minimize the number of bus transactions, aligning it to 512 bytes
1527 * boundaries could be beneficial, performance wise
1528 */
1529#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1530
Luciano Coelhocf27d862011-04-01 21:08:23 +03001531static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001532{
1533 struct sk_buff *skb;
1534 struct ieee80211_hdr_3addr *hdr;
1535 unsigned int dummy_packet_size;
1536
1537 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1538 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1539
1540 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001541 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001542 wl1271_warning("Failed to allocate a dummy packet skb");
1543 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001544 }
1545
1546 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1547
1548 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1549 memset(hdr, 0, sizeof(*hdr));
1550 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001551 IEEE80211_STYPE_NULLFUNC |
1552 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001553
Ido Yariv990f5de2011-03-31 10:06:59 +02001554 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001555
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001556 /* Dummy packets require the TID to be management */
1557 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001558
1559 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001560 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001561 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001562
Ido Yariv990f5de2011-03-31 10:06:59 +02001563 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001564}
1565
Ido Yariv990f5de2011-03-31 10:06:59 +02001566
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001567static struct notifier_block wl1271_dev_notifier = {
1568 .notifier_call = wl1271_dev_notify,
1569};
1570
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001571#ifdef CONFIG_PM
Eliad Peller94390642011-05-13 11:57:13 +03001572
Eliad Peller0603d892011-10-05 11:55:51 +02001573static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1574 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001575{
Eliad Pellere85d1622011-06-27 13:06:43 +03001576 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001577
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001578 mutex_lock(&wl->mutex);
1579
Eliad Peller53d40d02011-10-10 10:13:02 +02001580 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001581 goto out_unlock;
1582
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001583 ret = wl1271_ps_elp_wakeup(wl);
1584 if (ret < 0)
1585 goto out_unlock;
1586
Eliad Peller0603d892011-10-05 11:55:51 +02001587 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001588
1589 wl1271_ps_elp_sleep(wl);
1590out_unlock:
1591 mutex_unlock(&wl->mutex);
1592 return ret;
1593
1594}
1595
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001596static int wl1271_configure_suspend(struct wl1271 *wl,
1597 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001598{
Eliad Peller536129c2011-10-05 11:55:45 +02001599 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001600 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001601 return 0;
1602}
1603
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001604static void wl1271_configure_resume(struct wl1271 *wl,
1605 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001606{
1607 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001608 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001609
Eyal Shapirad6bf9ad2012-01-31 11:57:20 +02001610 if (!is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001611 return;
1612
1613 mutex_lock(&wl->mutex);
1614 ret = wl1271_ps_elp_wakeup(wl);
1615 if (ret < 0)
1616 goto out;
1617
Eyal Shapirad6bf9ad2012-01-31 11:57:20 +02001618 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller94390642011-05-13 11:57:13 +03001619
1620 wl1271_ps_elp_sleep(wl);
1621out:
1622 mutex_unlock(&wl->mutex);
1623}
1624
Eliad Peller402e48612011-05-13 11:57:09 +03001625static int wl1271_op_suspend(struct ieee80211_hw *hw,
1626 struct cfg80211_wowlan *wow)
1627{
1628 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001629 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001630 int ret;
1631
Eliad Peller402e48612011-05-13 11:57:09 +03001632 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001633 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001634
Eliad Peller4a859df2011-06-06 12:21:52 +03001635 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001636 wl12xx_for_each_wlvif(wl, wlvif) {
1637 ret = wl1271_configure_suspend(wl, wlvif);
1638 if (ret < 0) {
1639 wl1271_warning("couldn't prepare device to suspend");
1640 return ret;
1641 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001642 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001643 /* flush any remaining work */
1644 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001645
1646 /*
1647 * disable and re-enable interrupts in order to flush
1648 * the threaded_irq
1649 */
1650 wl1271_disable_interrupts(wl);
1651
1652 /*
1653 * set suspended flag to avoid triggering a new threaded_irq
1654 * work. no need for spinlock as interrupts are disabled.
1655 */
1656 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1657
1658 wl1271_enable_interrupts(wl);
1659 flush_work(&wl->tx_work);
Eliad Peller4a859df2011-06-06 12:21:52 +03001660 flush_delayed_work(&wl->elp_work);
1661
Eliad Peller402e48612011-05-13 11:57:09 +03001662 return 0;
1663}
1664
1665static int wl1271_op_resume(struct ieee80211_hw *hw)
1666{
1667 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001668 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001669 unsigned long flags;
1670 bool run_irq_work = false;
1671
Eliad Peller402e48612011-05-13 11:57:09 +03001672 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1673 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001674 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001675
1676 /*
1677 * re-enable irq_work enqueuing, and call irq_work directly if
1678 * there is a pending work.
1679 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001680 spin_lock_irqsave(&wl->wl_lock, flags);
1681 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1682 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1683 run_irq_work = true;
1684 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001685
Eliad Peller4a859df2011-06-06 12:21:52 +03001686 if (run_irq_work) {
1687 wl1271_debug(DEBUG_MAC80211,
1688 "run postponed irq_work directly");
1689 wl1271_irq(0, wl);
1690 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001691 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001692 wl12xx_for_each_wlvif(wl, wlvif) {
1693 wl1271_configure_resume(wl, wlvif);
1694 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001695 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001696
Eliad Peller402e48612011-05-13 11:57:09 +03001697 return 0;
1698}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001699#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001700
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001701static int wl1271_op_start(struct ieee80211_hw *hw)
1702{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001703 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1704
1705 /*
1706 * We have to delay the booting of the hardware because
1707 * we need to know the local MAC address before downloading and
1708 * initializing the firmware. The MAC address cannot be changed
1709 * after boot, and without the proper MAC address, the firmware
1710 * will not function properly.
1711 *
1712 * The MAC address is first known when the corresponding interface
1713 * is added. That is where we will initialize the hardware.
1714 */
1715
Eliad Pellercdaac622012-01-31 11:57:16 +02001716 wl1271_error("wl12xx is in an ustable state (fw api update is "
1717 "taking place). skip this commit when bisecting");
1718 return -EBUSY;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001719}
1720
1721static void wl1271_op_stop(struct ieee80211_hw *hw)
1722{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001723 struct wl1271 *wl = hw->priv;
1724 int i;
1725
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001726 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001727
Ido Yariv46b0cc92012-01-11 09:42:41 +02001728 /*
1729 * Interrupts must be disabled before setting the state to OFF.
1730 * Otherwise, the interrupt handler might be called and exit without
1731 * reading the interrupt status.
1732 */
1733 wl1271_disable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001734 mutex_lock(&wl->mutex);
1735 if (wl->state == WL1271_STATE_OFF) {
1736 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001737
1738 /*
1739 * This will not necessarily enable interrupts as interrupts
1740 * may have been disabled when op_stop was called. It will,
1741 * however, balance the above call to disable_interrupts().
1742 */
1743 wl1271_enable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001744 return;
1745 }
Ido Yariv46b0cc92012-01-11 09:42:41 +02001746
Eliad Pellerbaf62772011-10-10 10:12:52 +02001747 /*
1748 * this must be before the cancel_work calls below, so that the work
1749 * functions don't perform further work.
1750 */
1751 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001752 mutex_unlock(&wl->mutex);
1753
1754 mutex_lock(&wl_list_mutex);
1755 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001756 mutex_unlock(&wl_list_mutex);
1757
Eliad Pellerbaf62772011-10-10 10:12:52 +02001758 wl1271_flush_deferred_work(wl);
1759 cancel_delayed_work_sync(&wl->scan_complete_work);
1760 cancel_work_sync(&wl->netstack_work);
1761 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001762 cancel_delayed_work_sync(&wl->elp_work);
1763
1764 /* let's notify MAC80211 about the remaining pending TX frames */
1765 wl12xx_tx_reset(wl, true);
1766 mutex_lock(&wl->mutex);
1767
1768 wl1271_power_off(wl);
1769
1770 wl->band = IEEE80211_BAND_2GHZ;
1771
1772 wl->rx_counter = 0;
1773 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1774 wl->tx_blocks_available = 0;
1775 wl->tx_allocated_blocks = 0;
1776 wl->tx_results_count = 0;
1777 wl->tx_packets_count = 0;
1778 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001779 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1780 wl->ap_fw_ps_map = 0;
1781 wl->ap_ps_map = 0;
1782 wl->sched_scanning = false;
1783 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1784 memset(wl->links_map, 0, sizeof(wl->links_map));
1785 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1786 wl->active_sta_count = 0;
1787
1788 /* The system link is always allocated */
1789 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1790
1791 /*
1792 * this is performed after the cancel_work calls and the associated
1793 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1794 * get executed before all these vars have been reset.
1795 */
1796 wl->flags = 0;
1797
1798 wl->tx_blocks_freed = 0;
1799
1800 for (i = 0; i < NUM_TX_QUEUES; i++) {
1801 wl->tx_pkts_freed[i] = 0;
1802 wl->tx_allocated_pkts[i] = 0;
1803 }
1804
1805 wl1271_debugfs_reset(wl);
1806
1807 kfree(wl->fw_status);
1808 wl->fw_status = NULL;
1809 kfree(wl->tx_res_if);
1810 wl->tx_res_if = NULL;
1811 kfree(wl->target_mem_map);
1812 wl->target_mem_map = NULL;
1813
1814 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001815}
1816
Eliad Pellere5a359f2011-10-10 10:13:15 +02001817static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1818{
1819 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1820 WL12XX_MAX_RATE_POLICIES);
1821 if (policy >= WL12XX_MAX_RATE_POLICIES)
1822 return -EBUSY;
1823
1824 __set_bit(policy, wl->rate_policies_map);
1825 *idx = policy;
1826 return 0;
1827}
1828
1829static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1830{
1831 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1832 return;
1833
1834 __clear_bit(*idx, wl->rate_policies_map);
1835 *idx = WL12XX_MAX_RATE_POLICIES;
1836}
1837
Eliad Peller536129c2011-10-05 11:55:45 +02001838static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001839{
Eliad Peller536129c2011-10-05 11:55:45 +02001840 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001841 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001842 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001843 return WL1271_ROLE_P2P_GO;
1844 else
1845 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001846
1847 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001848 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001849 return WL1271_ROLE_P2P_CL;
1850 else
1851 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001852
Eliad Peller227e81e2011-08-14 13:17:26 +03001853 case BSS_TYPE_IBSS:
1854 return WL1271_ROLE_IBSS;
1855
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001856 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001857 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001858 }
1859 return WL12XX_INVALID_ROLE_TYPE;
1860}
1861
Eliad Peller83587502011-10-10 10:12:53 +02001862static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001863{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001864 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001865 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001866
Eliad Peller48e93e42011-10-10 10:12:58 +02001867 /* clear everything but the persistent data */
1868 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001869
1870 switch (ieee80211_vif_type_p2p(vif)) {
1871 case NL80211_IFTYPE_P2P_CLIENT:
1872 wlvif->p2p = 1;
1873 /* fall-through */
1874 case NL80211_IFTYPE_STATION:
1875 wlvif->bss_type = BSS_TYPE_STA_BSS;
1876 break;
1877 case NL80211_IFTYPE_ADHOC:
1878 wlvif->bss_type = BSS_TYPE_IBSS;
1879 break;
1880 case NL80211_IFTYPE_P2P_GO:
1881 wlvif->p2p = 1;
1882 /* fall-through */
1883 case NL80211_IFTYPE_AP:
1884 wlvif->bss_type = BSS_TYPE_AP_BSS;
1885 break;
1886 default:
1887 wlvif->bss_type = MAX_BSS_TYPE;
1888 return -EOPNOTSUPP;
1889 }
1890
Eliad Peller0603d892011-10-05 11:55:51 +02001891 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001892 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001893 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001894
Eliad Pellere936bbe2011-10-05 11:55:56 +02001895 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1896 wlvif->bss_type == BSS_TYPE_IBSS) {
1897 /* init sta/ibss data */
1898 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001899 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1900 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1901 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001902 } else {
1903 /* init ap data */
1904 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1905 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001906 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1907 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1908 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1909 wl12xx_allocate_rate_policy(wl,
1910 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001911 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001912
Eliad Peller83587502011-10-10 10:12:53 +02001913 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1914 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001915 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001916 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001917 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001918 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1919
Eliad Peller1b92f152011-10-10 10:13:09 +02001920 /*
1921 * mac80211 configures some values globally, while we treat them
1922 * per-interface. thus, on init, we have to copy them from wl
1923 */
1924 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001925 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001926 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02001927
Eliad Peller9eb599e2011-10-10 10:12:59 +02001928 INIT_WORK(&wlvif->rx_streaming_enable_work,
1929 wl1271_rx_streaming_enable_work);
1930 INIT_WORK(&wlvif->rx_streaming_disable_work,
1931 wl1271_rx_streaming_disable_work);
Eliad Peller87627212011-10-10 10:12:54 +02001932 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001933
Eliad Peller9eb599e2011-10-10 10:12:59 +02001934 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1935 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001936 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001937}
1938
Eliad Peller1d095472011-10-10 10:12:49 +02001939static bool wl12xx_init_fw(struct wl1271 *wl)
1940{
1941 int retries = WL1271_BOOT_RETRIES;
1942 bool booted = false;
1943 struct wiphy *wiphy = wl->hw->wiphy;
1944 int ret;
1945
1946 while (retries) {
1947 retries--;
1948 ret = wl1271_chip_wakeup(wl);
1949 if (ret < 0)
1950 goto power_off;
1951
1952 ret = wl1271_boot(wl);
1953 if (ret < 0)
1954 goto power_off;
1955
1956 ret = wl1271_hw_init(wl);
1957 if (ret < 0)
1958 goto irq_disable;
1959
1960 booted = true;
1961 break;
1962
1963irq_disable:
1964 mutex_unlock(&wl->mutex);
1965 /* Unlocking the mutex in the middle of handling is
1966 inherently unsafe. In this case we deem it safe to do,
1967 because we need to let any possibly pending IRQ out of
1968 the system (and while we are WL1271_STATE_OFF the IRQ
1969 work function will not do anything.) Also, any other
1970 possible concurrent operations will fail due to the
1971 current state, hence the wl1271 struct should be safe. */
1972 wl1271_disable_interrupts(wl);
1973 wl1271_flush_deferred_work(wl);
1974 cancel_work_sync(&wl->netstack_work);
1975 mutex_lock(&wl->mutex);
1976power_off:
1977 wl1271_power_off(wl);
1978 }
1979
1980 if (!booted) {
1981 wl1271_error("firmware boot failed despite %d retries",
1982 WL1271_BOOT_RETRIES);
1983 goto out;
1984 }
1985
1986 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
1987
1988 /* update hw/fw version info in wiphy struct */
1989 wiphy->hw_version = wl->chip.id;
1990 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1991 sizeof(wiphy->fw_version));
1992
1993 /*
1994 * Now we know if 11a is supported (info from the NVS), so disable
1995 * 11a channels if not supported
1996 */
1997 if (!wl->enable_11a)
1998 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1999
2000 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2001 wl->enable_11a ? "" : "not ");
2002
2003 wl->state = WL1271_STATE_ON;
2004out:
2005 return booted;
2006}
2007
Eliad Peller92e712d2011-12-18 20:25:43 +02002008static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2009{
2010 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2011}
2012
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002013static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2014 struct ieee80211_vif *vif)
2015{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002016 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002017 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002018 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002019 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002020 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002021
Johannes Bergea086352012-01-19 09:29:58 +01002022 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2023 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002024
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002025 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002026 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002027
2028 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002029 ret = wl1271_ps_elp_wakeup(wl);
2030 if (ret < 0)
2031 goto out_unlock;
2032
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002033 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002034 wl1271_debug(DEBUG_MAC80211,
2035 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002036 ret = -EBUSY;
2037 goto out;
2038 }
2039
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002040 /*
2041 * in some very corner case HW recovery scenarios its possible to
2042 * get here before __wl1271_op_remove_interface is complete, so
2043 * opt out if that is the case.
2044 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002045 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2046 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002047 ret = -EBUSY;
2048 goto out;
2049 }
2050
Eliad Peller83587502011-10-10 10:12:53 +02002051 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002052 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002053 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002054
Eliad Peller252efa42011-10-05 11:56:00 +02002055 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002056 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002057 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2058 ret = -EINVAL;
2059 goto out;
2060 }
Eliad Peller1d095472011-10-10 10:12:49 +02002061
Eliad Peller784f6942011-10-05 11:55:39 +02002062 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002063 * TODO: after the nvs issue will be solved, move this block
2064 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002065 */
Eliad Peller1d095472011-10-10 10:12:49 +02002066 if (wl->state == WL1271_STATE_OFF) {
2067 /*
2068 * we still need this in order to configure the fw
2069 * while uploading the nvs
2070 */
Luciano Coelho5e037e72011-12-23 09:32:17 +02002071 memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002072
Eliad Peller1d095472011-10-10 10:12:49 +02002073 booted = wl12xx_init_fw(wl);
2074 if (!booted) {
2075 ret = -EINVAL;
2076 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002077 }
Eliad Peller1d095472011-10-10 10:12:49 +02002078 }
Eliad Peller04e80792011-08-14 13:17:09 +03002079
Eliad Peller1d095472011-10-10 10:12:49 +02002080 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2081 wlvif->bss_type == BSS_TYPE_IBSS) {
2082 /*
2083 * The device role is a special role used for
2084 * rx and tx frames prior to association (as
2085 * the STA role can get packets only from
2086 * its associated bssid)
2087 */
Eliad Peller784f6942011-10-05 11:55:39 +02002088 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002089 WL1271_ROLE_DEVICE,
2090 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002091 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002092 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002093 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002094
Eliad Peller1d095472011-10-10 10:12:49 +02002095 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2096 role_type, &wlvif->role_id);
2097 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002098 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002099
2100 ret = wl1271_init_vif_specific(wl, vif);
2101 if (ret < 0)
2102 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002103
2104 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002105 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002106 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002107
2108 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2109 wl->ap_count++;
2110 else
2111 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002112out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002113 wl1271_ps_elp_sleep(wl);
2114out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002115 mutex_unlock(&wl->mutex);
2116
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002117 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002118 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002119 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002120 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002121
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002122 return ret;
2123}
2124
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002125static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002126 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002127 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002128{
Eliad Peller536129c2011-10-05 11:55:45 +02002129 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002130 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002131
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002132 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002133
Eliad Peller10c8cd02011-10-10 10:13:06 +02002134 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2135 return;
2136
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002137 wl->vif = NULL;
2138
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002139 /* because of hardware recovery, we may get here twice */
2140 if (wl->state != WL1271_STATE_ON)
2141 return;
2142
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002143 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002144
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002145 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002146 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002147 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002148
Eliad Pellerbaf62772011-10-10 10:12:52 +02002149 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2150 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002151 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002152 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002153 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002154 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002155 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002156 }
2157
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002158 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2159 /* disable active roles */
2160 ret = wl1271_ps_elp_wakeup(wl);
2161 if (ret < 0)
2162 goto deinit;
2163
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002164 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2165 wlvif->bss_type == BSS_TYPE_IBSS) {
2166 if (wl12xx_dev_role_started(wlvif))
2167 wl12xx_stop_dev(wl, wlvif);
2168
Eliad Peller7edebf52011-10-05 11:55:52 +02002169 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002170 if (ret < 0)
2171 goto deinit;
2172 }
2173
Eliad Peller0603d892011-10-05 11:55:51 +02002174 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002175 if (ret < 0)
2176 goto deinit;
2177
2178 wl1271_ps_elp_sleep(wl);
2179 }
2180deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002181 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002182 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002183
2184 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2185 wlvif->bss_type == BSS_TYPE_IBSS) {
2186 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2187 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2188 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2189 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2190 } else {
2191 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2192 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2193 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2194 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2195 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2196 wl12xx_free_rate_policy(wl,
2197 &wlvif->ap.ucast_rate_idx[i]);
2198 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002199
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002200 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002201 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002202 if (wl->last_wlvif == wlvif)
2203 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002204 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002205 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002206 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002207 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002208
Eliad Pellera4e41302011-10-11 11:49:15 +02002209 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2210 wl->ap_count--;
2211 else
2212 wl->sta_count--;
2213
Eliad Pellerbaf62772011-10-10 10:12:52 +02002214 mutex_unlock(&wl->mutex);
Eyal Shapirad6bf9ad2012-01-31 11:57:20 +02002215
Eliad Peller9eb599e2011-10-10 10:12:59 +02002216 del_timer_sync(&wlvif->rx_streaming_timer);
2217 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2218 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002219
Eliad Pellerbaf62772011-10-10 10:12:52 +02002220 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002221}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002222
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002223static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2224 struct ieee80211_vif *vif)
2225{
2226 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002227 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002228 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002229
2230 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002231
2232 if (wl->state == WL1271_STATE_OFF ||
2233 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2234 goto out;
2235
Juuso Oikarinen67353292010-11-18 15:19:02 +02002236 /*
2237 * wl->vif can be null here if someone shuts down the interface
2238 * just when hardware recovery has been started.
2239 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002240 wl12xx_for_each_wlvif(wl, iter) {
2241 if (iter != wlvif)
2242 continue;
2243
Eliad Peller536129c2011-10-05 11:55:45 +02002244 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002245 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002246 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002247 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002248out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002249 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002250 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002251}
2252
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002253static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2254 struct ieee80211_vif *vif,
2255 enum nl80211_iftype new_type, bool p2p)
2256{
2257 wl1271_op_remove_interface(hw, vif);
2258
2259 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2260 vif->p2p = p2p;
2261 return wl1271_op_add_interface(hw, vif);
2262}
2263
Eliad Peller87fbcb02011-10-05 11:55:41 +02002264static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2265 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002266{
2267 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002268 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002269
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002270 /*
2271 * One of the side effects of the JOIN command is that is clears
2272 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2273 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002274 * Currently the only valid scenario for JOIN during association
2275 * is on roaming, in which case we will also be given new keys.
2276 * Keep the below message for now, unless it starts bothering
2277 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002278 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002279 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002280 wl1271_info("JOIN while associated.");
2281
2282 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002283 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002284
Eliad Peller227e81e2011-08-14 13:17:26 +03002285 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002286 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002287 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002288 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002289 if (ret < 0)
2290 goto out;
2291
Eliad Pellerba8447f2011-10-10 10:13:00 +02002292 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002293 goto out;
2294
2295 /*
2296 * The join command disable the keep-alive mode, shut down its process,
2297 * and also clear the template config, so we need to reset it all after
2298 * the join. The acx_aid starts the keep-alive process, and the order
2299 * of the commands below is relevant.
2300 */
Eliad Peller0603d892011-10-05 11:55:51 +02002301 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002302 if (ret < 0)
2303 goto out;
2304
Eliad Peller0603d892011-10-05 11:55:51 +02002305 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002306 if (ret < 0)
2307 goto out;
2308
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002309 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002310 if (ret < 0)
2311 goto out;
2312
Eliad Peller0603d892011-10-05 11:55:51 +02002313 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2314 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002315 ACX_KEEP_ALIVE_TPL_VALID);
2316 if (ret < 0)
2317 goto out;
2318
2319out:
2320 return ret;
2321}
2322
Eliad Peller0603d892011-10-05 11:55:51 +02002323static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002324{
2325 int ret;
2326
Eliad Peller52630c52011-10-10 10:13:08 +02002327 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002328 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2329
Shahar Levi6d158ff2011-09-08 13:01:33 +03002330 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002331 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002332 }
2333
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002334 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002335 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002336 if (ret < 0)
2337 goto out;
2338
Oz Krakowskib992c682011-06-26 10:36:02 +03002339 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002340 wlvif->tx_security_last_seq_lsb = 0;
2341 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002342
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002343out:
2344 return ret;
2345}
2346
Eliad Peller87fbcb02011-10-05 11:55:41 +02002347static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002348{
Eliad Peller1b92f152011-10-10 10:13:09 +02002349 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002350 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002351}
2352
Eliad Peller87fbcb02011-10-05 11:55:41 +02002353static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2354 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002355{
2356 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002357 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2358
2359 if (idle == cur_idle)
2360 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002361
2362 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002363 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002364 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002365 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002366 if (ret < 0)
2367 goto out;
2368 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002369 wlvif->rate_set =
2370 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2371 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002372 if (ret < 0)
2373 goto out;
2374 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002375 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002376 ACX_KEEP_ALIVE_TPL_INVALID);
2377 if (ret < 0)
2378 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002379 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002380 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002381 /* The current firmware only supports sched_scan in idle */
2382 if (wl->sched_scanning) {
2383 wl1271_scan_sched_scan_stop(wl);
2384 ieee80211_sched_scan_stopped(wl->hw);
2385 }
2386
Eliad Peller679a6732011-10-11 11:55:44 +02002387 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002388 if (ret < 0)
2389 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002390 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002391 }
2392
2393out:
2394 return ret;
2395}
2396
Eliad Peller9f259c42011-10-10 10:13:12 +02002397static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2398 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002399{
Eliad Peller9f259c42011-10-10 10:13:12 +02002400 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2401 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002402
2403 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2404
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002405 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002406 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002407 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002408 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002409 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002410 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002411 wlvif->band = conf->channel->band;
2412 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002413
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002414 if (!is_ap) {
2415 /*
2416 * FIXME: the mac80211 should really provide a fixed
2417 * rate to use here. for now, just use the smallest
2418 * possible rate for the band as a fixed rate for
2419 * association frames and other control messages.
2420 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002421 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002422 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002423
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002424 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002425 wl1271_tx_min_rate_get(wl,
2426 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002427 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002428 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002429 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002430 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002431
Eliad Pellerba8447f2011-10-10 10:13:00 +02002432 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2433 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002434 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002435 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002436 ret = wl12xx_croc(wl,
2437 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002438 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002439 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002440 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002441 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002442 if (ret < 0)
2443 wl1271_warning("cmd join on channel "
2444 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002445 } else {
2446 /*
2447 * change the ROC channel. do it only if we are
2448 * not idle. otherwise, CROC will be called
2449 * anyway.
2450 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002451 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002452 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002453 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002454 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002455 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002456
Eliad Peller679a6732011-10-11 11:55:44 +02002457 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002458 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002459 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002460 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002461 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002462 }
2463 }
2464
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002465 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002466 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2467 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002468
2469 /*
2470 * We enter PSM only if we're already associated.
2471 * If we're not, we'll enter it when joining an SSID,
2472 * through the bss_info_changed() hook.
2473 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002474 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002475 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002476 ret = wl1271_ps_set_mode(wl, wlvif,
2477 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002478 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002479 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002480 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002481 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002482 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002483
Eliad Pellerc29bb002011-10-10 10:13:03 +02002484 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002485
Eliad Pellerc29bb002011-10-10 10:13:03 +02002486 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002487 ret = wl1271_ps_set_mode(wl, wlvif,
2488 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002489 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002490 }
2491
Eliad Peller6bd65022011-10-10 10:13:11 +02002492 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002493 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002494 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002495 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002496
Eliad Peller6bd65022011-10-10 10:13:11 +02002497 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002498 }
2499
Eliad Peller9f259c42011-10-10 10:13:12 +02002500 return 0;
2501}
2502
2503static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2504{
2505 struct wl1271 *wl = hw->priv;
2506 struct wl12xx_vif *wlvif;
2507 struct ieee80211_conf *conf = &hw->conf;
2508 int channel, ret = 0;
2509
2510 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2511
2512 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2513 " changed 0x%x",
2514 channel,
2515 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2516 conf->power_level,
2517 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2518 changed);
2519
2520 /*
2521 * mac80211 will go to idle nearly immediately after transmitting some
2522 * frames, such as the deauth. To make sure those frames reach the air,
2523 * wait here until the TX queue is fully flushed.
2524 */
2525 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2526 (conf->flags & IEEE80211_CONF_IDLE))
2527 wl1271_tx_flush(wl);
2528
2529 mutex_lock(&wl->mutex);
2530
2531 /* we support configuring the channel and band even while off */
2532 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2533 wl->band = conf->channel->band;
2534 wl->channel = channel;
2535 }
2536
2537 if (changed & IEEE80211_CONF_CHANGE_POWER)
2538 wl->power_level = conf->power_level;
2539
2540 if (unlikely(wl->state == WL1271_STATE_OFF))
2541 goto out;
2542
2543 ret = wl1271_ps_elp_wakeup(wl);
2544 if (ret < 0)
2545 goto out;
2546
2547 /* configure each interface */
2548 wl12xx_for_each_wlvif(wl, wlvif) {
2549 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2550 if (ret < 0)
2551 goto out_sleep;
2552 }
2553
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002554out_sleep:
2555 wl1271_ps_elp_sleep(wl);
2556
2557out:
2558 mutex_unlock(&wl->mutex);
2559
2560 return ret;
2561}
2562
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002563struct wl1271_filter_params {
2564 bool enabled;
2565 int mc_list_length;
2566 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2567};
2568
Jiri Pirko22bedad2010-04-01 21:22:57 +00002569static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2570 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002571{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002572 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002573 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002574 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002575
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002576 if (unlikely(wl->state == WL1271_STATE_OFF))
2577 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002578
Juuso Oikarinen74441132009-10-13 12:47:53 +03002579 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002580 if (!fp) {
2581 wl1271_error("Out of memory setting filters.");
2582 return 0;
2583 }
2584
2585 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002586 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002587 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2588 fp->enabled = false;
2589 } else {
2590 fp->enabled = true;
2591 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002592 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002593 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002594 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002595 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002596 }
2597
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002598 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002599}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002600
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002601#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2602 FIF_ALLMULTI | \
2603 FIF_FCSFAIL | \
2604 FIF_BCN_PRBRESP_PROMISC | \
2605 FIF_CONTROL | \
2606 FIF_OTHER_BSS)
2607
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002608static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2609 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002610 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002611{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002612 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002613 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002614 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002615
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002616 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002617
Arik Nemtsov7d057862010-10-16 19:25:35 +02002618 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2619 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002620
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002621 mutex_lock(&wl->mutex);
2622
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002623 *total &= WL1271_SUPPORTED_FILTERS;
2624 changed &= WL1271_SUPPORTED_FILTERS;
2625
2626 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002627 goto out;
2628
Ido Yariva6208652011-03-01 15:14:41 +02002629 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002630 if (ret < 0)
2631 goto out;
2632
Eliad Peller6e8cd332011-10-10 10:13:13 +02002633 wl12xx_for_each_wlvif(wl, wlvif) {
2634 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2635 if (*total & FIF_ALLMULTI)
2636 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2637 false,
2638 NULL, 0);
2639 else if (fp)
2640 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2641 fp->enabled,
2642 fp->mc_list,
2643 fp->mc_list_length);
2644 if (ret < 0)
2645 goto out_sleep;
2646 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002647 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002648
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002649 /*
2650 * the fw doesn't provide an api to configure the filters. instead,
2651 * the filters configuration is based on the active roles / ROC
2652 * state.
2653 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002654
2655out_sleep:
2656 wl1271_ps_elp_sleep(wl);
2657
2658out:
2659 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002660 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002661}
2662
Eliad Peller170d0e62011-10-05 11:56:06 +02002663static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2664 u8 id, u8 key_type, u8 key_size,
2665 const u8 *key, u8 hlid, u32 tx_seq_32,
2666 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002667{
2668 struct wl1271_ap_key *ap_key;
2669 int i;
2670
2671 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2672
2673 if (key_size > MAX_KEY_SIZE)
2674 return -EINVAL;
2675
2676 /*
2677 * Find next free entry in ap_keys. Also check we are not replacing
2678 * an existing key.
2679 */
2680 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002681 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002682 break;
2683
Eliad Peller170d0e62011-10-05 11:56:06 +02002684 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002685 wl1271_warning("trying to record key replacement");
2686 return -EINVAL;
2687 }
2688 }
2689
2690 if (i == MAX_NUM_KEYS)
2691 return -EBUSY;
2692
2693 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2694 if (!ap_key)
2695 return -ENOMEM;
2696
2697 ap_key->id = id;
2698 ap_key->key_type = key_type;
2699 ap_key->key_size = key_size;
2700 memcpy(ap_key->key, key, key_size);
2701 ap_key->hlid = hlid;
2702 ap_key->tx_seq_32 = tx_seq_32;
2703 ap_key->tx_seq_16 = tx_seq_16;
2704
Eliad Peller170d0e62011-10-05 11:56:06 +02002705 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002706 return 0;
2707}
2708
Eliad Peller170d0e62011-10-05 11:56:06 +02002709static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002710{
2711 int i;
2712
2713 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002714 kfree(wlvif->ap.recorded_keys[i]);
2715 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002716 }
2717}
2718
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002719static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002720{
2721 int i, ret = 0;
2722 struct wl1271_ap_key *key;
2723 bool wep_key_added = false;
2724
2725 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002726 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002727 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002728 break;
2729
Eliad Peller170d0e62011-10-05 11:56:06 +02002730 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002731 hlid = key->hlid;
2732 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002733 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002734
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002735 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002736 key->id, key->key_type,
2737 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002738 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002739 key->tx_seq_16);
2740 if (ret < 0)
2741 goto out;
2742
2743 if (key->key_type == KEY_WEP)
2744 wep_key_added = true;
2745 }
2746
2747 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002748 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002749 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002750 if (ret < 0)
2751 goto out;
2752 }
2753
2754out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002755 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002756 return ret;
2757}
2758
Eliad Peller536129c2011-10-05 11:55:45 +02002759static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2760 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002761 u8 key_size, const u8 *key, u32 tx_seq_32,
2762 u16 tx_seq_16, struct ieee80211_sta *sta)
2763{
2764 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002765 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002766
2767 if (is_ap) {
2768 struct wl1271_station *wl_sta;
2769 u8 hlid;
2770
2771 if (sta) {
2772 wl_sta = (struct wl1271_station *)sta->drv_priv;
2773 hlid = wl_sta->hlid;
2774 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002775 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002776 }
2777
Eliad Peller53d40d02011-10-10 10:13:02 +02002778 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002779 /*
2780 * We do not support removing keys after AP shutdown.
2781 * Pretend we do to make mac80211 happy.
2782 */
2783 if (action != KEY_ADD_OR_REPLACE)
2784 return 0;
2785
Eliad Peller170d0e62011-10-05 11:56:06 +02002786 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002787 key_type, key_size,
2788 key, hlid, tx_seq_32,
2789 tx_seq_16);
2790 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002791 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002792 id, key_type, key_size,
2793 key, hlid, tx_seq_32,
2794 tx_seq_16);
2795 }
2796
2797 if (ret < 0)
2798 return ret;
2799 } else {
2800 const u8 *addr;
2801 static const u8 bcast_addr[ETH_ALEN] = {
2802 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2803 };
2804
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002805 /*
2806 * A STA set to GEM cipher requires 2 tx spare blocks.
2807 * Return to default value when GEM cipher key is removed
2808 */
2809 if (key_type == KEY_GEM) {
2810 if (action == KEY_ADD_OR_REPLACE)
2811 wl->tx_spare_blocks = 2;
2812 else if (action == KEY_REMOVE)
2813 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2814 }
2815
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002816 addr = sta ? sta->addr : bcast_addr;
2817
2818 if (is_zero_ether_addr(addr)) {
2819 /* We dont support TX only encryption */
2820 return -EOPNOTSUPP;
2821 }
2822
2823 /* The wl1271 does not allow to remove unicast keys - they
2824 will be cleared automatically on next CMD_JOIN. Ignore the
2825 request silently, as we dont want the mac80211 to emit
2826 an error message. */
2827 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2828 return 0;
2829
Eliad Peller010d3d32011-08-14 13:17:31 +03002830 /* don't remove key if hlid was already deleted */
2831 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002832 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002833 return 0;
2834
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002835 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002836 id, key_type, key_size,
2837 key, addr, tx_seq_32,
2838 tx_seq_16);
2839 if (ret < 0)
2840 return ret;
2841
2842 /* the default WEP key needs to be configured at least once */
2843 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002844 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002845 wlvif->default_key,
2846 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002847 if (ret < 0)
2848 return ret;
2849 }
2850 }
2851
2852 return 0;
2853}
2854
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002855static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2856 struct ieee80211_vif *vif,
2857 struct ieee80211_sta *sta,
2858 struct ieee80211_key_conf *key_conf)
2859{
2860 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002861 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002862 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002863 u32 tx_seq_32 = 0;
2864 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002865 u8 key_type;
2866
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002867 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2868
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002869 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002870 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002871 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002872 key_conf->keylen, key_conf->flags);
2873 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2874
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002875 mutex_lock(&wl->mutex);
2876
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002877 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2878 ret = -EAGAIN;
2879 goto out_unlock;
2880 }
2881
Ido Yariva6208652011-03-01 15:14:41 +02002882 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002883 if (ret < 0)
2884 goto out_unlock;
2885
Johannes Berg97359d12010-08-10 09:46:38 +02002886 switch (key_conf->cipher) {
2887 case WLAN_CIPHER_SUITE_WEP40:
2888 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002889 key_type = KEY_WEP;
2890
2891 key_conf->hw_key_idx = key_conf->keyidx;
2892 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002893 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002894 key_type = KEY_TKIP;
2895
2896 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002897 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2898 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002899 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002900 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002901 key_type = KEY_AES;
2902
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002903 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002904 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2905 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002906 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002907 case WL1271_CIPHER_SUITE_GEM:
2908 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002909 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2910 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002911 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002912 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002913 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002914
2915 ret = -EOPNOTSUPP;
2916 goto out_sleep;
2917 }
2918
2919 switch (cmd) {
2920 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002921 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002922 key_conf->keyidx, key_type,
2923 key_conf->keylen, key_conf->key,
2924 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002925 if (ret < 0) {
2926 wl1271_error("Could not add or replace key");
2927 goto out_sleep;
2928 }
2929 break;
2930
2931 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002932 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002933 key_conf->keyidx, key_type,
2934 key_conf->keylen, key_conf->key,
2935 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002936 if (ret < 0) {
2937 wl1271_error("Could not remove key");
2938 goto out_sleep;
2939 }
2940 break;
2941
2942 default:
2943 wl1271_error("Unsupported key cmd 0x%x", cmd);
2944 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002945 break;
2946 }
2947
2948out_sleep:
2949 wl1271_ps_elp_sleep(wl);
2950
2951out_unlock:
2952 mutex_unlock(&wl->mutex);
2953
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002954 return ret;
2955}
2956
2957static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002958 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002959 struct cfg80211_scan_request *req)
2960{
2961 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02002962 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2963
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002964 int ret;
2965 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002966 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002967
2968 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2969
2970 if (req->n_ssids) {
2971 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002972 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002973 }
2974
2975 mutex_lock(&wl->mutex);
2976
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002977 if (wl->state == WL1271_STATE_OFF) {
2978 /*
2979 * We cannot return -EBUSY here because cfg80211 will expect
2980 * a call to ieee80211_scan_completed if we do - in this case
2981 * there won't be any call.
2982 */
2983 ret = -EAGAIN;
2984 goto out;
2985 }
2986
Ido Yariva6208652011-03-01 15:14:41 +02002987 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002988 if (ret < 0)
2989 goto out;
2990
Eliad Peller92e712d2011-12-18 20:25:43 +02002991 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
2992 test_bit(wlvif->role_id, wl->roc_map)) {
2993 /* don't allow scanning right now */
2994 ret = -EBUSY;
2995 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03002996 }
2997
Eliad Peller92e712d2011-12-18 20:25:43 +02002998 /* cancel ROC before scanning */
2999 if (wl12xx_dev_role_started(wlvif))
Eliad Pellerc059beb2012-01-31 11:57:17 +02003000 wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller92e712d2011-12-18 20:25:43 +02003001
Eliad Peller784f6942011-10-05 11:55:39 +02003002 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003003out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003004 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003005out:
3006 mutex_unlock(&wl->mutex);
3007
3008 return ret;
3009}
3010
Eliad Peller73ecce32011-06-27 13:06:45 +03003011static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3012 struct ieee80211_vif *vif)
3013{
3014 struct wl1271 *wl = hw->priv;
3015 int ret;
3016
3017 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3018
3019 mutex_lock(&wl->mutex);
3020
3021 if (wl->state == WL1271_STATE_OFF)
3022 goto out;
3023
3024 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3025 goto out;
3026
3027 ret = wl1271_ps_elp_wakeup(wl);
3028 if (ret < 0)
3029 goto out;
3030
3031 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3032 ret = wl1271_scan_stop(wl);
3033 if (ret < 0)
3034 goto out_sleep;
3035 }
3036 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3037 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003038 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003039 wl->scan.req = NULL;
3040 ieee80211_scan_completed(wl->hw, true);
3041
3042out_sleep:
3043 wl1271_ps_elp_sleep(wl);
3044out:
3045 mutex_unlock(&wl->mutex);
3046
3047 cancel_delayed_work_sync(&wl->scan_complete_work);
3048}
3049
Luciano Coelho33c2c062011-05-10 14:46:02 +03003050static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3051 struct ieee80211_vif *vif,
3052 struct cfg80211_sched_scan_request *req,
3053 struct ieee80211_sched_scan_ies *ies)
3054{
3055 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003056 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003057 int ret;
3058
3059 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3060
3061 mutex_lock(&wl->mutex);
3062
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003063 if (wl->state == WL1271_STATE_OFF) {
3064 ret = -EAGAIN;
3065 goto out;
3066 }
3067
Luciano Coelho33c2c062011-05-10 14:46:02 +03003068 ret = wl1271_ps_elp_wakeup(wl);
3069 if (ret < 0)
3070 goto out;
3071
Eliad Peller536129c2011-10-05 11:55:45 +02003072 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003073 if (ret < 0)
3074 goto out_sleep;
3075
Eliad Peller536129c2011-10-05 11:55:45 +02003076 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003077 if (ret < 0)
3078 goto out_sleep;
3079
3080 wl->sched_scanning = true;
3081
3082out_sleep:
3083 wl1271_ps_elp_sleep(wl);
3084out:
3085 mutex_unlock(&wl->mutex);
3086 return ret;
3087}
3088
3089static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3090 struct ieee80211_vif *vif)
3091{
3092 struct wl1271 *wl = hw->priv;
3093 int ret;
3094
3095 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3096
3097 mutex_lock(&wl->mutex);
3098
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003099 if (wl->state == WL1271_STATE_OFF)
3100 goto out;
3101
Luciano Coelho33c2c062011-05-10 14:46:02 +03003102 ret = wl1271_ps_elp_wakeup(wl);
3103 if (ret < 0)
3104 goto out;
3105
3106 wl1271_scan_sched_scan_stop(wl);
3107
3108 wl1271_ps_elp_sleep(wl);
3109out:
3110 mutex_unlock(&wl->mutex);
3111}
3112
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003113static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3114{
3115 struct wl1271 *wl = hw->priv;
3116 int ret = 0;
3117
3118 mutex_lock(&wl->mutex);
3119
3120 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3121 ret = -EAGAIN;
3122 goto out;
3123 }
3124
Ido Yariva6208652011-03-01 15:14:41 +02003125 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003126 if (ret < 0)
3127 goto out;
3128
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003129 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003130 if (ret < 0)
3131 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3132
3133 wl1271_ps_elp_sleep(wl);
3134
3135out:
3136 mutex_unlock(&wl->mutex);
3137
3138 return ret;
3139}
3140
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003141static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3142{
3143 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003144 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003145 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003146
3147 mutex_lock(&wl->mutex);
3148
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003149 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3150 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003151 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003152 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003153
Ido Yariva6208652011-03-01 15:14:41 +02003154 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003155 if (ret < 0)
3156 goto out;
3157
Eliad Peller6e8cd332011-10-10 10:13:13 +02003158 wl12xx_for_each_wlvif(wl, wlvif) {
3159 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3160 if (ret < 0)
3161 wl1271_warning("set rts threshold failed: %d", ret);
3162 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003163 wl1271_ps_elp_sleep(wl);
3164
3165out:
3166 mutex_unlock(&wl->mutex);
3167
3168 return ret;
3169}
3170
Eliad Peller1fe9f162011-10-05 11:55:48 +02003171static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003172 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003173{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003174 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003175 u8 ssid_len;
3176 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3177 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003178
Eliad Peller889cb362011-05-01 09:56:45 +03003179 if (!ptr) {
3180 wl1271_error("No SSID in IEs!");
3181 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003182 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003183
Eliad Peller889cb362011-05-01 09:56:45 +03003184 ssid_len = ptr[1];
3185 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3186 wl1271_error("SSID is too long!");
3187 return -EINVAL;
3188 }
3189
Eliad Peller1fe9f162011-10-05 11:55:48 +02003190 wlvif->ssid_len = ssid_len;
3191 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003192 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003193}
3194
Eliad Pellerd48055d2011-09-15 12:07:04 +03003195static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3196{
3197 int len;
3198 const u8 *next, *end = skb->data + skb->len;
3199 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3200 skb->len - ieoffset);
3201 if (!ie)
3202 return;
3203 len = ie[1] + 2;
3204 next = ie + len;
3205 memmove(ie, next, end - next);
3206 skb_trim(skb, skb->len - len);
3207}
3208
Eliad Peller26b4bf22011-09-15 12:07:05 +03003209static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3210 unsigned int oui, u8 oui_type,
3211 int ieoffset)
3212{
3213 int len;
3214 const u8 *next, *end = skb->data + skb->len;
3215 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3216 skb->data + ieoffset,
3217 skb->len - ieoffset);
3218 if (!ie)
3219 return;
3220 len = ie[1] + 2;
3221 next = ie + len;
3222 memmove(ie, next, end - next);
3223 skb_trim(skb, skb->len - len);
3224}
3225
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003226static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3227 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003228{
Eliad Pellercdaac622012-01-31 11:57:16 +02003229 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003230 struct sk_buff *skb;
3231 int ret;
3232
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003233 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003234 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003235 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003236
Eliad Pellercdaac622012-01-31 11:57:16 +02003237 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov560f0022011-11-08 18:46:54 +02003238 CMD_TEMPL_AP_PROBE_RESPONSE,
3239 skb->data,
3240 skb->len, 0,
3241 rates);
3242
3243 dev_kfree_skb(skb);
3244 return ret;
3245}
3246
3247static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3248 struct ieee80211_vif *vif,
3249 u8 *probe_rsp_data,
3250 size_t probe_rsp_len,
3251 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003252{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003253 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3254 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003255 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3256 int ssid_ie_offset, ie_offset, templ_len;
3257 const u8 *ptr;
3258
3259 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003260 if (wlvif->ssid_len > 0)
Eliad Pellercdaac622012-01-31 11:57:16 +02003261 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003262 CMD_TEMPL_AP_PROBE_RESPONSE,
3263 probe_rsp_data,
3264 probe_rsp_len, 0,
3265 rates);
3266
3267 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3268 wl1271_error("probe_rsp template too big");
3269 return -EINVAL;
3270 }
3271
3272 /* start searching from IE offset */
3273 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3274
3275 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3276 probe_rsp_len - ie_offset);
3277 if (!ptr) {
3278 wl1271_error("No SSID in beacon!");
3279 return -EINVAL;
3280 }
3281
3282 ssid_ie_offset = ptr - probe_rsp_data;
3283 ptr += (ptr[1] + 2);
3284
3285 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3286
3287 /* insert SSID from bss_conf */
3288 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3289 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3290 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3291 bss_conf->ssid, bss_conf->ssid_len);
3292 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3293
3294 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3295 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3296 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3297
Eliad Pellercdaac622012-01-31 11:57:16 +02003298 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003299 CMD_TEMPL_AP_PROBE_RESPONSE,
3300 probe_rsp_templ,
3301 templ_len, 0,
3302 rates);
3303}
3304
Arik Nemtsove78a2872010-10-16 19:07:21 +02003305static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003306 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003307 struct ieee80211_bss_conf *bss_conf,
3308 u32 changed)
3309{
Eliad Peller0603d892011-10-05 11:55:51 +02003310 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003311 int ret = 0;
3312
3313 if (changed & BSS_CHANGED_ERP_SLOT) {
3314 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003315 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003316 else
Eliad Peller0603d892011-10-05 11:55:51 +02003317 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003318 if (ret < 0) {
3319 wl1271_warning("Set slot time failed %d", ret);
3320 goto out;
3321 }
3322 }
3323
3324 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3325 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003326 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003327 else
Eliad Peller0603d892011-10-05 11:55:51 +02003328 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003329 }
3330
3331 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3332 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003333 ret = wl1271_acx_cts_protect(wl, wlvif,
3334 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003335 else
Eliad Peller0603d892011-10-05 11:55:51 +02003336 ret = wl1271_acx_cts_protect(wl, wlvif,
3337 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003338 if (ret < 0) {
3339 wl1271_warning("Set ctsprotect failed %d", ret);
3340 goto out;
3341 }
3342 }
3343
3344out:
3345 return ret;
3346}
3347
3348static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3349 struct ieee80211_vif *vif,
3350 struct ieee80211_bss_conf *bss_conf,
3351 u32 changed)
3352{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003353 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003354 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003355 int ret = 0;
3356
3357 if ((changed & BSS_CHANGED_BEACON_INT)) {
3358 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3359 bss_conf->beacon_int);
3360
Eliad Peller6a899792011-10-05 11:55:58 +02003361 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003362 }
3363
Arik Nemtsov560f0022011-11-08 18:46:54 +02003364 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3365 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003366 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3367 wl1271_debug(DEBUG_AP, "probe response updated");
3368 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3369 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003370 }
3371
Arik Nemtsove78a2872010-10-16 19:07:21 +02003372 if ((changed & BSS_CHANGED_BEACON)) {
3373 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003374 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003375 int ieoffset = offsetof(struct ieee80211_mgmt,
3376 u.beacon.variable);
3377 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3378 u16 tmpl_id;
3379
Arik Nemtsov560f0022011-11-08 18:46:54 +02003380 if (!beacon) {
3381 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003382 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003383 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003384
3385 wl1271_debug(DEBUG_MASTER, "beacon updated");
3386
Eliad Peller1fe9f162011-10-05 11:55:48 +02003387 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003388 if (ret < 0) {
3389 dev_kfree_skb(beacon);
3390 goto out;
3391 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003392 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003393 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3394 CMD_TEMPL_BEACON;
Eliad Pellercdaac622012-01-31 11:57:16 +02003395 ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003396 beacon->data,
3397 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003398 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003399 if (ret < 0) {
3400 dev_kfree_skb(beacon);
3401 goto out;
3402 }
3403
Arik Nemtsov560f0022011-11-08 18:46:54 +02003404 /*
3405 * In case we already have a probe-resp beacon set explicitly
3406 * by usermode, don't use the beacon data.
3407 */
3408 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3409 goto end_bcn;
3410
Eliad Pellerd48055d2011-09-15 12:07:04 +03003411 /* remove TIM ie from probe response */
3412 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3413
Eliad Peller26b4bf22011-09-15 12:07:05 +03003414 /*
3415 * remove p2p ie from probe response.
3416 * the fw reponds to probe requests that don't include
3417 * the p2p ie. probe requests with p2p ie will be passed,
3418 * and will be responded by the supplicant (the spec
3419 * forbids including the p2p ie when responding to probe
3420 * requests that didn't include it).
3421 */
3422 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3423 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3424
Arik Nemtsove78a2872010-10-16 19:07:21 +02003425 hdr = (struct ieee80211_hdr *) beacon->data;
3426 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3427 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003428 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003429 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003430 beacon->data,
3431 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003432 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003433 else
Eliad Pellercdaac622012-01-31 11:57:16 +02003434 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003435 CMD_TEMPL_PROBE_RESPONSE,
3436 beacon->data,
3437 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003438 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003439end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003440 dev_kfree_skb(beacon);
3441 if (ret < 0)
3442 goto out;
3443 }
3444
3445out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003446 if (ret != 0)
3447 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003448 return ret;
3449}
3450
3451/* AP mode changes */
3452static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003453 struct ieee80211_vif *vif,
3454 struct ieee80211_bss_conf *bss_conf,
3455 u32 changed)
3456{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003457 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003458 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003459
Arik Nemtsove78a2872010-10-16 19:07:21 +02003460 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3461 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003462
Eliad Peller87fbcb02011-10-05 11:55:41 +02003463 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003464 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003465 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003466 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003467
Eliad Peller87fbcb02011-10-05 11:55:41 +02003468 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003469 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003470 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003471 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003472 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003473
Eliad Peller784f6942011-10-05 11:55:39 +02003474 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003475 if (ret < 0)
3476 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003477 }
3478
Arik Nemtsove78a2872010-10-16 19:07:21 +02003479 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3480 if (ret < 0)
3481 goto out;
3482
3483 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3484 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003485 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003486 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003487 if (ret < 0)
3488 goto out;
3489
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003490 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003491 if (ret < 0)
3492 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003493
Eliad Peller53d40d02011-10-10 10:13:02 +02003494 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003495 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003496 }
3497 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003498 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003499 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003500 if (ret < 0)
3501 goto out;
3502
Eliad Peller53d40d02011-10-10 10:13:02 +02003503 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003504 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3505 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003506 wl1271_debug(DEBUG_AP, "stopped AP");
3507 }
3508 }
3509 }
3510
Eliad Peller0603d892011-10-05 11:55:51 +02003511 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003512 if (ret < 0)
3513 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003514
3515 /* Handle HT information change */
3516 if ((changed & BSS_CHANGED_HT) &&
3517 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003518 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003519 bss_conf->ht_operation_mode);
3520 if (ret < 0) {
3521 wl1271_warning("Set ht information failed %d", ret);
3522 goto out;
3523 }
3524 }
3525
Arik Nemtsove78a2872010-10-16 19:07:21 +02003526out:
3527 return;
3528}
3529
3530/* STA/IBSS mode changes */
3531static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3532 struct ieee80211_vif *vif,
3533 struct ieee80211_bss_conf *bss_conf,
3534 u32 changed)
3535{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003536 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003537 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003538 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003539 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003540 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003541 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003542 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003543 bool sta_exists = false;
3544 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003545
3546 if (is_ibss) {
3547 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3548 changed);
3549 if (ret < 0)
3550 goto out;
3551 }
3552
Eliad Peller227e81e2011-08-14 13:17:26 +03003553 if (changed & BSS_CHANGED_IBSS) {
3554 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003555 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003556 ibss_joined = true;
3557 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003558 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3559 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003560 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003561 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003562 }
3563 }
3564 }
3565
3566 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003567 do_join = true;
3568
3569 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003570 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003571 do_join = true;
3572
Eliad Peller227e81e2011-08-14 13:17:26 +03003573 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003574 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3575 bss_conf->enable_beacon ? "enabled" : "disabled");
3576
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003577 do_join = true;
3578 }
3579
Eliad Pellerc31e4942011-10-23 08:21:55 +02003580 if (changed & BSS_CHANGED_IDLE) {
3581 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3582 if (ret < 0)
3583 wl1271_warning("idle mode change failed %d", ret);
3584 }
3585
Arik Nemtsove78a2872010-10-16 19:07:21 +02003586 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003587 bool enable = false;
3588 if (bss_conf->cqm_rssi_thold)
3589 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003590 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003591 bss_conf->cqm_rssi_thold,
3592 bss_conf->cqm_rssi_hyst);
3593 if (ret < 0)
3594 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003595 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003596 }
3597
Eliad Peller7db4ee62012-01-24 18:18:42 +02003598 if (changed & BSS_CHANGED_BSSID &&
3599 (is_ibss || bss_conf->assoc))
Eliad Pellercdf09492011-10-05 11:55:44 +02003600 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003601 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003602 if (ret < 0)
3603 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003604
Eliad Peller784f6942011-10-05 11:55:39 +02003605 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003606 if (ret < 0)
3607 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003608
Eliad Pellerfa287b82010-12-26 09:27:50 +01003609 /* Need to update the BSSID (for filtering etc) */
3610 do_join = true;
3611 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003612
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003613 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3614 rcu_read_lock();
3615 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3616 if (!sta)
3617 goto sta_not_found;
3618
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003619 /* save the supp_rates of the ap */
3620 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3621 if (sta->ht_cap.ht_supported)
3622 sta_rate_set |=
3623 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003624 sta_ht_cap = sta->ht_cap;
3625 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003626
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003627sta_not_found:
3628 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003629 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003630
Arik Nemtsove78a2872010-10-16 19:07:21 +02003631 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003632 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003633 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003634 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003635 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003636 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003637
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003638 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003639 * use basic rates from AP, and determine lowest rate
3640 * to use with control frames.
3641 */
3642 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003643 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003644 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003645 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003646 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003647 wl1271_tx_min_rate_get(wl,
3648 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003649 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003650 wlvif->rate_set =
3651 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003652 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003653 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003654 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003655 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003656 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003657
3658 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003659 * with wl1271, we don't need to update the
3660 * beacon_int and dtim_period, because the firmware
3661 * updates it by itself when the first beacon is
3662 * received after a join.
3663 */
Eliad Peller6840e372011-10-05 11:55:50 +02003664 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003665 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003666 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003667
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003668 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003669 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003670 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003671 dev_kfree_skb(wlvif->probereq);
3672 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003673 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003674 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003675 ieoffset = offsetof(struct ieee80211_mgmt,
3676 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003677 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003678
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003679 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003680 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003681 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003682 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003683 } else {
3684 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003685 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003686 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3687 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003688 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003689 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3690 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003691 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003692
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003693 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003694 dev_kfree_skb(wlvif->probereq);
3695 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003696
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003697 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003698 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003699
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003700 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003701 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003702 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003703 wl1271_tx_min_rate_get(wl,
3704 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003705 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003706 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003707 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003708
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003709 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003710 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003711
3712 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003713 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003714 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003715 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003716
3717 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003718 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003719 u32 conf_flags = wl->hw->conf.flags;
3720 /*
3721 * we might have to disable roc, if there was
3722 * no IF_OPER_UP notification.
3723 */
3724 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003725 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003726 if (ret < 0)
3727 goto out;
3728 }
3729 /*
3730 * (we also need to disable roc in case of
3731 * roaming on the same channel. until we will
3732 * have a better flow...)
3733 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003734 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3735 ret = wl12xx_croc(wl,
3736 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003737 if (ret < 0)
3738 goto out;
3739 }
3740
Eliad Peller0603d892011-10-05 11:55:51 +02003741 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003742 if (!(conf_flags & IEEE80211_CONF_IDLE))
3743 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003744 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003745 }
3746 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003747
Eliad Pellerd192d262011-05-24 14:33:08 +03003748 if (changed & BSS_CHANGED_IBSS) {
3749 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3750 bss_conf->ibss_joined);
3751
3752 if (bss_conf->ibss_joined) {
3753 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003754 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003755 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003756 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003757 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003758 wl1271_tx_min_rate_get(wl,
3759 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003760
Shahar Levi06b660e2011-09-05 13:54:36 +03003761 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003762 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3763 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003764 if (ret < 0)
3765 goto out;
3766 }
3767 }
3768
Eliad Peller0603d892011-10-05 11:55:51 +02003769 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003770 if (ret < 0)
3771 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003772
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003773 if (changed & BSS_CHANGED_ARP_FILTER) {
3774 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003775 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003776
Eliad Pellerc5312772010-12-09 11:31:27 +02003777 if (bss_conf->arp_addr_cnt == 1 &&
3778 bss_conf->arp_filter_enabled) {
3779 /*
3780 * The template should have been configured only upon
3781 * association. however, it seems that the correct ip
3782 * isn't being set (when sending), so we have to
3783 * reconfigure the template upon every ip change.
3784 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003785 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003786 if (ret < 0) {
3787 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003788 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003789 }
3790
Eliad Peller0603d892011-10-05 11:55:51 +02003791 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003792 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003793 addr);
3794 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003795 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003796
3797 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003798 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003799 }
3800
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003801 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003802 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003803 if (ret < 0) {
3804 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003805 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003806 }
Eliad Peller251c1772011-08-14 13:17:17 +03003807
3808 /* ROC until connected (after EAPOL exchange) */
3809 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003810 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003811 if (ret < 0)
3812 goto out;
3813
Eliad Pellerba8447f2011-10-10 10:13:00 +02003814 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003815 ieee80211_get_operstate(vif));
3816 }
3817 /*
3818 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003819 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003820 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003821 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003822 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003823 if (ret < 0)
3824 goto out;
3825 }
Eliad Peller05dba352011-08-23 16:37:01 +03003826
3827 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003828 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3829 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003830 enum wl1271_cmd_ps_mode mode;
3831
3832 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003833 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003834 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003835 true);
3836 if (ret < 0)
3837 goto out;
3838 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003839 }
3840
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003841 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003842 if (sta_exists) {
3843 if ((changed & BSS_CHANGED_HT) &&
3844 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003845 ret = wl1271_acx_set_ht_capabilities(wl,
3846 &sta_ht_cap,
3847 true,
Eliad Peller154da672011-10-05 11:55:53 +02003848 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003849 if (ret < 0) {
3850 wl1271_warning("Set ht cap true failed %d",
3851 ret);
3852 goto out;
3853 }
3854 }
3855 /* handle new association without HT and disassociation */
3856 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003857 ret = wl1271_acx_set_ht_capabilities(wl,
3858 &sta_ht_cap,
3859 false,
Eliad Peller154da672011-10-05 11:55:53 +02003860 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003861 if (ret < 0) {
3862 wl1271_warning("Set ht cap false failed %d",
3863 ret);
3864 goto out;
3865 }
3866 }
3867 }
3868
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003869 /* Handle HT information change. Done after join. */
3870 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003871 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003872 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003873 bss_conf->ht_operation_mode);
3874 if (ret < 0) {
3875 wl1271_warning("Set ht information failed %d", ret);
3876 goto out;
3877 }
3878 }
3879
Arik Nemtsove78a2872010-10-16 19:07:21 +02003880out:
3881 return;
3882}
3883
3884static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3885 struct ieee80211_vif *vif,
3886 struct ieee80211_bss_conf *bss_conf,
3887 u32 changed)
3888{
3889 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003890 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3891 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003892 int ret;
3893
3894 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3895 (int)changed);
3896
3897 mutex_lock(&wl->mutex);
3898
3899 if (unlikely(wl->state == WL1271_STATE_OFF))
3900 goto out;
3901
Eliad Peller10c8cd02011-10-10 10:13:06 +02003902 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3903 goto out;
3904
Ido Yariva6208652011-03-01 15:14:41 +02003905 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003906 if (ret < 0)
3907 goto out;
3908
3909 if (is_ap)
3910 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3911 else
3912 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3913
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003914 wl1271_ps_elp_sleep(wl);
3915
3916out:
3917 mutex_unlock(&wl->mutex);
3918}
3919
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003920static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3921 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003922 const struct ieee80211_tx_queue_params *params)
3923{
3924 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003925 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003926 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003927 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003928
3929 mutex_lock(&wl->mutex);
3930
3931 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3932
Kalle Valo4695dc92010-03-18 12:26:38 +02003933 if (params->uapsd)
3934 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3935 else
3936 ps_scheme = CONF_PS_SCHEME_LEGACY;
3937
Eliad Peller5b37ddf2011-12-18 20:25:40 +02003938 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003939 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003940
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003941 ret = wl1271_ps_elp_wakeup(wl);
3942 if (ret < 0)
3943 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003944
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003945 /*
3946 * the txop is confed in units of 32us by the mac80211,
3947 * we need us
3948 */
Eliad Peller0603d892011-10-05 11:55:51 +02003949 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003950 params->cw_min, params->cw_max,
3951 params->aifs, params->txop << 5);
3952 if (ret < 0)
3953 goto out_sleep;
3954
Eliad Peller0603d892011-10-05 11:55:51 +02003955 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003956 CONF_CHANNEL_TYPE_EDCF,
3957 wl1271_tx_get_queue(queue),
3958 ps_scheme, CONF_ACK_POLICY_LEGACY,
3959 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003960
3961out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003962 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003963
3964out:
3965 mutex_unlock(&wl->mutex);
3966
3967 return ret;
3968}
3969
Eliad Peller37a41b42011-09-21 14:06:11 +03003970static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
3971 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003972{
3973
3974 struct wl1271 *wl = hw->priv;
Eliad Peller9c531142012-01-31 11:57:18 +02003975 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003976 u64 mactime = ULLONG_MAX;
3977 int ret;
3978
3979 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3980
3981 mutex_lock(&wl->mutex);
3982
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003983 if (unlikely(wl->state == WL1271_STATE_OFF))
3984 goto out;
3985
Ido Yariva6208652011-03-01 15:14:41 +02003986 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003987 if (ret < 0)
3988 goto out;
3989
Eliad Peller9c531142012-01-31 11:57:18 +02003990 ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003991 if (ret < 0)
3992 goto out_sleep;
3993
3994out_sleep:
3995 wl1271_ps_elp_sleep(wl);
3996
3997out:
3998 mutex_unlock(&wl->mutex);
3999 return mactime;
4000}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004001
John W. Linvilleece550d2010-07-28 16:41:06 -04004002static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4003 struct survey_info *survey)
4004{
4005 struct wl1271 *wl = hw->priv;
4006 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004007
John W. Linvilleece550d2010-07-28 16:41:06 -04004008 if (idx != 0)
4009 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004010
John W. Linvilleece550d2010-07-28 16:41:06 -04004011 survey->channel = conf->channel;
4012 survey->filled = SURVEY_INFO_NOISE_DBM;
4013 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004014
John W. Linvilleece550d2010-07-28 16:41:06 -04004015 return 0;
4016}
4017
Arik Nemtsov409622e2011-02-23 00:22:29 +02004018static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004019 struct wl12xx_vif *wlvif,
4020 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004021{
4022 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004023 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004024
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004025
4026 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004027 wl1271_warning("could not allocate HLID - too much stations");
4028 return -EBUSY;
4029 }
4030
4031 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004032 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4033 if (ret < 0) {
4034 wl1271_warning("could not allocate HLID - too many links");
4035 return -EBUSY;
4036 }
4037
4038 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004039 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004040 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004041 return 0;
4042}
4043
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004044void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004045{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004046 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004047 return;
4048
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004049 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004050 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004051 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004052 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004053 __clear_bit(hlid, &wl->ap_ps_map);
4054 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004055 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004056 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004057}
4058
4059static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4060 struct ieee80211_vif *vif,
4061 struct ieee80211_sta *sta)
4062{
4063 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004064 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004065 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004066 int ret = 0;
4067 u8 hlid;
4068
4069 mutex_lock(&wl->mutex);
4070
4071 if (unlikely(wl->state == WL1271_STATE_OFF))
4072 goto out;
4073
Eliad Peller536129c2011-10-05 11:55:45 +02004074 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004075 goto out;
4076
4077 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4078
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004079 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004080 if (ret < 0)
4081 goto out;
4082
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004083 wl_sta = (struct wl1271_station *)sta->drv_priv;
4084 hlid = wl_sta->hlid;
4085
Ido Yariva6208652011-03-01 15:14:41 +02004086 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004087 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004088 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004089
Eliad Peller1b92f152011-10-10 10:13:09 +02004090 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004091 if (ret < 0)
4092 goto out_sleep;
4093
Eliad Pellerb67476e2011-08-14 13:17:23 +03004094 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4095 if (ret < 0)
4096 goto out_sleep;
4097
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004098 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4099 if (ret < 0)
4100 goto out_sleep;
4101
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004102out_sleep:
4103 wl1271_ps_elp_sleep(wl);
4104
Arik Nemtsov409622e2011-02-23 00:22:29 +02004105out_free_sta:
4106 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004107 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004108
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004109out:
4110 mutex_unlock(&wl->mutex);
4111 return ret;
4112}
4113
4114static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4115 struct ieee80211_vif *vif,
4116 struct ieee80211_sta *sta)
4117{
4118 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004119 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004120 struct wl1271_station *wl_sta;
4121 int ret = 0, id;
4122
4123 mutex_lock(&wl->mutex);
4124
4125 if (unlikely(wl->state == WL1271_STATE_OFF))
4126 goto out;
4127
Eliad Peller536129c2011-10-05 11:55:45 +02004128 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004129 goto out;
4130
4131 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4132
4133 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004134 id = wl_sta->hlid;
4135 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004136 goto out;
4137
Ido Yariva6208652011-03-01 15:14:41 +02004138 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004139 if (ret < 0)
4140 goto out;
4141
Eliad Pellerc690ec82011-08-14 13:17:07 +03004142 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004143 if (ret < 0)
4144 goto out_sleep;
4145
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004146 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004147
4148out_sleep:
4149 wl1271_ps_elp_sleep(wl);
4150
4151out:
4152 mutex_unlock(&wl->mutex);
4153 return ret;
4154}
4155
Luciano Coelho4623ec72011-03-21 19:26:41 +02004156static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4157 struct ieee80211_vif *vif,
4158 enum ieee80211_ampdu_mlme_action action,
4159 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4160 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004161{
4162 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004163 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004164 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004165 u8 hlid, *ba_bitmap;
4166
4167 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4168 tid);
4169
4170 /* sanity check - the fields in FW are only 8bits wide */
4171 if (WARN_ON(tid > 0xFF))
4172 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004173
4174 mutex_lock(&wl->mutex);
4175
4176 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4177 ret = -EAGAIN;
4178 goto out;
4179 }
4180
Eliad Peller536129c2011-10-05 11:55:45 +02004181 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004182 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004183 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004184 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004185 struct wl1271_station *wl_sta;
4186
4187 wl_sta = (struct wl1271_station *)sta->drv_priv;
4188 hlid = wl_sta->hlid;
4189 ba_bitmap = &wl->links[hlid].ba_bitmap;
4190 } else {
4191 ret = -EINVAL;
4192 goto out;
4193 }
4194
Ido Yariva6208652011-03-01 15:14:41 +02004195 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004196 if (ret < 0)
4197 goto out;
4198
Shahar Levi70559a02011-05-22 16:10:22 +03004199 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4200 tid, action);
4201
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004202 switch (action) {
4203 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004204 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004205 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004206 break;
4207 }
4208
4209 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4210 ret = -EBUSY;
4211 wl1271_error("exceeded max RX BA sessions");
4212 break;
4213 }
4214
4215 if (*ba_bitmap & BIT(tid)) {
4216 ret = -EINVAL;
4217 wl1271_error("cannot enable RX BA session on active "
4218 "tid: %d", tid);
4219 break;
4220 }
4221
4222 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4223 hlid);
4224 if (!ret) {
4225 *ba_bitmap |= BIT(tid);
4226 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004227 }
4228 break;
4229
4230 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004231 if (!(*ba_bitmap & BIT(tid))) {
4232 ret = -EINVAL;
4233 wl1271_error("no active RX BA session on tid: %d",
4234 tid);
4235 break;
4236 }
4237
4238 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4239 hlid);
4240 if (!ret) {
4241 *ba_bitmap &= ~BIT(tid);
4242 wl->ba_rx_session_count--;
4243 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004244 break;
4245
4246 /*
4247 * The BA initiator session management in FW independently.
4248 * Falling break here on purpose for all TX APDU commands.
4249 */
4250 case IEEE80211_AMPDU_TX_START:
4251 case IEEE80211_AMPDU_TX_STOP:
4252 case IEEE80211_AMPDU_TX_OPERATIONAL:
4253 ret = -EINVAL;
4254 break;
4255
4256 default:
4257 wl1271_error("Incorrect ampdu action id=%x\n", action);
4258 ret = -EINVAL;
4259 }
4260
4261 wl1271_ps_elp_sleep(wl);
4262
4263out:
4264 mutex_unlock(&wl->mutex);
4265
4266 return ret;
4267}
4268
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004269static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4270 struct ieee80211_vif *vif,
4271 const struct cfg80211_bitrate_mask *mask)
4272{
Eliad Peller83587502011-10-10 10:12:53 +02004273 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004274 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004275 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004276
4277 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4278 mask->control[NL80211_BAND_2GHZ].legacy,
4279 mask->control[NL80211_BAND_5GHZ].legacy);
4280
4281 mutex_lock(&wl->mutex);
4282
4283 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004284 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004285 wl1271_tx_enabled_rates_get(wl,
4286 mask->control[i].legacy,
4287 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004288
4289 if (unlikely(wl->state == WL1271_STATE_OFF))
4290 goto out;
4291
4292 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4293 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4294
4295 ret = wl1271_ps_elp_wakeup(wl);
4296 if (ret < 0)
4297 goto out;
4298
4299 wl1271_set_band_rate(wl, wlvif);
4300 wlvif->basic_rate =
4301 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4302 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4303
4304 wl1271_ps_elp_sleep(wl);
4305 }
4306out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004307 mutex_unlock(&wl->mutex);
4308
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004309 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004310}
4311
Shahar Levi6d158ff2011-09-08 13:01:33 +03004312static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4313 struct ieee80211_channel_switch *ch_switch)
4314{
4315 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004316 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004317 int ret;
4318
4319 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4320
4321 mutex_lock(&wl->mutex);
4322
4323 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004324 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4325 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4326 ieee80211_chswitch_done(vif, false);
4327 }
4328 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004329 }
4330
4331 ret = wl1271_ps_elp_wakeup(wl);
4332 if (ret < 0)
4333 goto out;
4334
Eliad Peller52630c52011-10-10 10:13:08 +02004335 /* TODO: change mac80211 to pass vif as param */
4336 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller8332f0f2012-01-31 11:57:19 +02004337 ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004338
Eliad Peller52630c52011-10-10 10:13:08 +02004339 if (!ret)
4340 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4341 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004342
4343 wl1271_ps_elp_sleep(wl);
4344
4345out:
4346 mutex_unlock(&wl->mutex);
4347}
4348
Arik Nemtsov33437892011-04-26 23:35:39 +03004349static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4350{
4351 struct wl1271 *wl = hw->priv;
4352 bool ret = false;
4353
4354 mutex_lock(&wl->mutex);
4355
4356 if (unlikely(wl->state == WL1271_STATE_OFF))
4357 goto out;
4358
4359 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004360 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004361out:
4362 mutex_unlock(&wl->mutex);
4363
4364 return ret;
4365}
4366
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004367/* can't be const, mac80211 writes to this */
4368static struct ieee80211_rate wl1271_rates[] = {
4369 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004370 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4371 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004372 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004373 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4374 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004375 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4376 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004377 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4378 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004379 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4380 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004381 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4382 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004383 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4384 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004385 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4386 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004387 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004388 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4389 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004390 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004391 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4392 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004393 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004394 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4395 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004396 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004397 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4398 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004399 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004400 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4401 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004402 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004403 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4404 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004405 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004406 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4407 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004408};
4409
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004410/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004411static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004412 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004413 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004414 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4415 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4416 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004417 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004418 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4419 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4420 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004421 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004422 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4423 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4424 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004425 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004426};
4427
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004428/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004429static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004430 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004431 7, /* CONF_HW_RXTX_RATE_MCS7 */
4432 6, /* CONF_HW_RXTX_RATE_MCS6 */
4433 5, /* CONF_HW_RXTX_RATE_MCS5 */
4434 4, /* CONF_HW_RXTX_RATE_MCS4 */
4435 3, /* CONF_HW_RXTX_RATE_MCS3 */
4436 2, /* CONF_HW_RXTX_RATE_MCS2 */
4437 1, /* CONF_HW_RXTX_RATE_MCS1 */
4438 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004439
4440 11, /* CONF_HW_RXTX_RATE_54 */
4441 10, /* CONF_HW_RXTX_RATE_48 */
4442 9, /* CONF_HW_RXTX_RATE_36 */
4443 8, /* CONF_HW_RXTX_RATE_24 */
4444
4445 /* TI-specific rate */
4446 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4447
4448 7, /* CONF_HW_RXTX_RATE_18 */
4449 6, /* CONF_HW_RXTX_RATE_12 */
4450 3, /* CONF_HW_RXTX_RATE_11 */
4451 5, /* CONF_HW_RXTX_RATE_9 */
4452 4, /* CONF_HW_RXTX_RATE_6 */
4453 2, /* CONF_HW_RXTX_RATE_5_5 */
4454 1, /* CONF_HW_RXTX_RATE_2 */
4455 0 /* CONF_HW_RXTX_RATE_1 */
4456};
4457
Shahar Levie8b03a22010-10-13 16:09:39 +02004458/* 11n STA capabilities */
4459#define HW_RX_HIGHEST_RATE 72
4460
Shahar Levi00d20102010-11-08 11:20:10 +00004461#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004462 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4463 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004464 .ht_supported = true, \
4465 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4466 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4467 .mcs = { \
4468 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4469 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4470 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4471 }, \
4472}
4473
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004474/* can't be const, mac80211 writes to this */
4475static struct ieee80211_supported_band wl1271_band_2ghz = {
4476 .channels = wl1271_channels,
4477 .n_channels = ARRAY_SIZE(wl1271_channels),
4478 .bitrates = wl1271_rates,
4479 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004480 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004481};
4482
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004483/* 5 GHz data rates for WL1273 */
4484static struct ieee80211_rate wl1271_rates_5ghz[] = {
4485 { .bitrate = 60,
4486 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4487 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4488 { .bitrate = 90,
4489 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4490 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4491 { .bitrate = 120,
4492 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4493 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4494 { .bitrate = 180,
4495 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4496 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4497 { .bitrate = 240,
4498 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4499 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4500 { .bitrate = 360,
4501 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4502 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4503 { .bitrate = 480,
4504 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4505 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4506 { .bitrate = 540,
4507 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4508 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4509};
4510
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004511/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004512static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004513 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4514 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4515 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4516 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4517 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4518 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4519 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4520 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4521 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4522 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4523 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4524 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4525 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4526 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4527 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4528 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4529 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4530 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4531 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4532 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4533 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4534 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4535 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4536 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4537 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4538 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4539 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4540 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4541 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4542 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4543 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4544 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4545 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4546 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004547};
4548
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004549/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004550static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004551 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004552 7, /* CONF_HW_RXTX_RATE_MCS7 */
4553 6, /* CONF_HW_RXTX_RATE_MCS6 */
4554 5, /* CONF_HW_RXTX_RATE_MCS5 */
4555 4, /* CONF_HW_RXTX_RATE_MCS4 */
4556 3, /* CONF_HW_RXTX_RATE_MCS3 */
4557 2, /* CONF_HW_RXTX_RATE_MCS2 */
4558 1, /* CONF_HW_RXTX_RATE_MCS1 */
4559 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004560
4561 7, /* CONF_HW_RXTX_RATE_54 */
4562 6, /* CONF_HW_RXTX_RATE_48 */
4563 5, /* CONF_HW_RXTX_RATE_36 */
4564 4, /* CONF_HW_RXTX_RATE_24 */
4565
4566 /* TI-specific rate */
4567 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4568
4569 3, /* CONF_HW_RXTX_RATE_18 */
4570 2, /* CONF_HW_RXTX_RATE_12 */
4571 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4572 1, /* CONF_HW_RXTX_RATE_9 */
4573 0, /* CONF_HW_RXTX_RATE_6 */
4574 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4575 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4576 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4577};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004578
4579static struct ieee80211_supported_band wl1271_band_5ghz = {
4580 .channels = wl1271_channels_5ghz,
4581 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4582 .bitrates = wl1271_rates_5ghz,
4583 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004584 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004585};
4586
Tobias Klausera0ea9492010-05-20 10:38:11 +02004587static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004588 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4589 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4590};
4591
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004592static const struct ieee80211_ops wl1271_ops = {
4593 .start = wl1271_op_start,
4594 .stop = wl1271_op_stop,
4595 .add_interface = wl1271_op_add_interface,
4596 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004597 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004598#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004599 .suspend = wl1271_op_suspend,
4600 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004601#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004602 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004603 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004604 .configure_filter = wl1271_op_configure_filter,
4605 .tx = wl1271_op_tx,
4606 .set_key = wl1271_op_set_key,
4607 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004608 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004609 .sched_scan_start = wl1271_op_sched_scan_start,
4610 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004611 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004612 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004613 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004614 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004615 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004616 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004617 .sta_add = wl1271_op_sta_add,
4618 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004619 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004620 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004621 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004622 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004623 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004624};
4625
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004626
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004627u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004628{
4629 u8 idx;
4630
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004631 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004632
4633 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4634 wl1271_error("Illegal RX rate from HW: %d", rate);
4635 return 0;
4636 }
4637
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004638 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004639 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4640 wl1271_error("Unsupported RX rate from HW: %d", rate);
4641 return 0;
4642 }
4643
4644 return idx;
4645}
4646
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004647static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4648 struct device_attribute *attr,
4649 char *buf)
4650{
4651 struct wl1271 *wl = dev_get_drvdata(dev);
4652 ssize_t len;
4653
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004654 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004655
4656 mutex_lock(&wl->mutex);
4657 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4658 wl->sg_enabled);
4659 mutex_unlock(&wl->mutex);
4660
4661 return len;
4662
4663}
4664
4665static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4666 struct device_attribute *attr,
4667 const char *buf, size_t count)
4668{
4669 struct wl1271 *wl = dev_get_drvdata(dev);
4670 unsigned long res;
4671 int ret;
4672
Luciano Coelho6277ed62011-04-01 17:49:54 +03004673 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004674 if (ret < 0) {
4675 wl1271_warning("incorrect value written to bt_coex_mode");
4676 return count;
4677 }
4678
4679 mutex_lock(&wl->mutex);
4680
4681 res = !!res;
4682
4683 if (res == wl->sg_enabled)
4684 goto out;
4685
4686 wl->sg_enabled = res;
4687
4688 if (wl->state == WL1271_STATE_OFF)
4689 goto out;
4690
Ido Yariva6208652011-03-01 15:14:41 +02004691 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004692 if (ret < 0)
4693 goto out;
4694
4695 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4696 wl1271_ps_elp_sleep(wl);
4697
4698 out:
4699 mutex_unlock(&wl->mutex);
4700 return count;
4701}
4702
4703static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4704 wl1271_sysfs_show_bt_coex_state,
4705 wl1271_sysfs_store_bt_coex_state);
4706
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004707static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4708 struct device_attribute *attr,
4709 char *buf)
4710{
4711 struct wl1271 *wl = dev_get_drvdata(dev);
4712 ssize_t len;
4713
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004714 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004715
4716 mutex_lock(&wl->mutex);
4717 if (wl->hw_pg_ver >= 0)
4718 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4719 else
4720 len = snprintf(buf, len, "n/a\n");
4721 mutex_unlock(&wl->mutex);
4722
4723 return len;
4724}
4725
Gery Kahn6f07b722011-07-18 14:21:49 +03004726static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004727 wl1271_sysfs_show_hw_pg_ver, NULL);
4728
Ido Yariv95dac04f2011-06-06 14:57:06 +03004729static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4730 struct bin_attribute *bin_attr,
4731 char *buffer, loff_t pos, size_t count)
4732{
4733 struct device *dev = container_of(kobj, struct device, kobj);
4734 struct wl1271 *wl = dev_get_drvdata(dev);
4735 ssize_t len;
4736 int ret;
4737
4738 ret = mutex_lock_interruptible(&wl->mutex);
4739 if (ret < 0)
4740 return -ERESTARTSYS;
4741
4742 /* Let only one thread read the log at a time, blocking others */
4743 while (wl->fwlog_size == 0) {
4744 DEFINE_WAIT(wait);
4745
4746 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4747 &wait,
4748 TASK_INTERRUPTIBLE);
4749
4750 if (wl->fwlog_size != 0) {
4751 finish_wait(&wl->fwlog_waitq, &wait);
4752 break;
4753 }
4754
4755 mutex_unlock(&wl->mutex);
4756
4757 schedule();
4758 finish_wait(&wl->fwlog_waitq, &wait);
4759
4760 if (signal_pending(current))
4761 return -ERESTARTSYS;
4762
4763 ret = mutex_lock_interruptible(&wl->mutex);
4764 if (ret < 0)
4765 return -ERESTARTSYS;
4766 }
4767
4768 /* Check if the fwlog is still valid */
4769 if (wl->fwlog_size < 0) {
4770 mutex_unlock(&wl->mutex);
4771 return 0;
4772 }
4773
4774 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4775 len = min(count, (size_t)wl->fwlog_size);
4776 wl->fwlog_size -= len;
4777 memcpy(buffer, wl->fwlog, len);
4778
4779 /* Make room for new messages */
4780 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4781
4782 mutex_unlock(&wl->mutex);
4783
4784 return len;
4785}
4786
4787static struct bin_attribute fwlog_attr = {
4788 .attr = {.name = "fwlog", .mode = S_IRUSR},
4789 .read = wl1271_sysfs_read_fwlog,
4790};
4791
Luciano Coelho5e037e72011-12-23 09:32:17 +02004792static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
4793{
4794 bool supported = false;
4795 u8 major, minor;
4796
4797 if (wl->chip.id == CHIP_ID_1283_PG20) {
4798 major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
4799 minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
4800
4801 /* in wl128x we have the MAC address if the PG is >= (2, 1) */
4802 if (major > 2 || (major == 2 && minor >= 1))
4803 supported = true;
4804 } else {
4805 major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
4806 minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
4807
4808 /* in wl127x we have the MAC address if the PG is >= (3, 1) */
4809 if (major == 3 && minor >= 1)
4810 supported = true;
4811 }
4812
4813 wl1271_debug(DEBUG_PROBE,
4814 "PG Ver major = %d minor = %d, MAC %s present",
4815 major, minor, supported ? "is" : "is not");
4816
4817 return supported;
4818}
4819
4820static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
4821 u32 oui, u32 nic, int n)
4822{
4823 int i;
4824
4825 wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
4826 oui, nic, n);
4827
4828 if (nic + n - 1 > 0xffffff)
4829 wl1271_warning("NIC part of the MAC address wraps around!");
4830
4831 for (i = 0; i < n; i++) {
4832 wl->addresses[i].addr[0] = (u8)(oui >> 16);
4833 wl->addresses[i].addr[1] = (u8)(oui >> 8);
4834 wl->addresses[i].addr[2] = (u8) oui;
4835 wl->addresses[i].addr[3] = (u8)(nic >> 16);
4836 wl->addresses[i].addr[4] = (u8)(nic >> 8);
4837 wl->addresses[i].addr[5] = (u8) nic;
4838 nic++;
4839 }
4840
4841 wl->hw->wiphy->n_addresses = n;
4842 wl->hw->wiphy->addresses = wl->addresses;
4843}
4844
4845static void wl12xx_get_fuse_mac(struct wl1271 *wl)
4846{
4847 u32 mac1, mac2;
4848
4849 wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
4850
4851 mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
4852 mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
4853
4854 /* these are the two parts of the BD_ADDR */
4855 wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
4856 ((mac1 & 0xff000000) >> 24);
4857 wl->fuse_nic_addr = mac1 & 0xffffff;
4858
4859 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
4860}
4861
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004862static int wl12xx_get_hw_info(struct wl1271 *wl)
4863{
4864 int ret;
4865 u32 die_info;
4866
4867 ret = wl12xx_set_power_on(wl);
4868 if (ret < 0)
4869 goto out;
4870
4871 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
4872
4873 if (wl->chip.id == CHIP_ID_1283_PG20)
4874 die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
4875 else
4876 die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
4877
4878 wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
4879
Luciano Coelho5e037e72011-12-23 09:32:17 +02004880 if (!wl12xx_mac_in_fuse(wl)) {
4881 wl->fuse_oui_addr = 0;
4882 wl->fuse_nic_addr = 0;
4883 } else {
4884 wl12xx_get_fuse_mac(wl);
4885 }
4886
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004887 wl1271_power_off(wl);
4888out:
4889 return ret;
4890}
4891
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004892static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004893{
4894 int ret;
Luciano Coelho5e037e72011-12-23 09:32:17 +02004895 u32 oui_addr = 0, nic_addr = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004896
4897 if (wl->mac80211_registered)
4898 return 0;
4899
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004900 ret = wl12xx_get_hw_info(wl);
4901 if (ret < 0) {
4902 wl1271_error("couldn't get hw info");
4903 goto out;
4904 }
4905
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004906 ret = wl1271_fetch_nvs(wl);
4907 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004908 /* NOTE: The wl->nvs->nvs element must be first, in
4909 * order to simplify the casting, we assume it is at
4910 * the beginning of the wl->nvs structure.
4911 */
4912 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004913
Luciano Coelho5e037e72011-12-23 09:32:17 +02004914 oui_addr =
4915 (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
4916 nic_addr =
4917 (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004918 }
4919
Luciano Coelho5e037e72011-12-23 09:32:17 +02004920 /* if the MAC address is zeroed in the NVS derive from fuse */
4921 if (oui_addr == 0 && nic_addr == 0) {
4922 oui_addr = wl->fuse_oui_addr;
4923 /* fuse has the BD_ADDR, the WLAN addresses are the next two */
4924 nic_addr = wl->fuse_nic_addr + 1;
4925 }
4926
4927 wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004928
4929 ret = ieee80211_register_hw(wl->hw);
4930 if (ret < 0) {
4931 wl1271_error("unable to register mac80211 hw: %d", ret);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004932 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004933 }
4934
4935 wl->mac80211_registered = true;
4936
Eliad Pellerd60080a2010-11-24 12:53:16 +02004937 wl1271_debugfs_init(wl);
4938
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004939 register_netdevice_notifier(&wl1271_dev_notifier);
4940
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004941 wl1271_notice("loaded");
4942
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004943out:
4944 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004945}
4946
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004947static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004948{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004949 if (wl->state == WL1271_STATE_PLT)
Ido Yarivf3df1332012-01-11 09:42:39 +02004950 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004951
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004952 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004953 ieee80211_unregister_hw(wl->hw);
4954 wl->mac80211_registered = false;
4955
4956}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004957
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004958static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004959{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004960 static const u32 cipher_suites[] = {
4961 WLAN_CIPHER_SUITE_WEP40,
4962 WLAN_CIPHER_SUITE_WEP104,
4963 WLAN_CIPHER_SUITE_TKIP,
4964 WLAN_CIPHER_SUITE_CCMP,
4965 WL1271_CIPHER_SUITE_GEM,
4966 };
4967
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004968 /* The tx descriptor buffer and the TKIP space. */
4969 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4970 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004971
4972 /* unit us */
4973 /* FIXME: find a proper value */
4974 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004975 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004976
4977 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004978 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004979 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004980 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004981 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004982 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004983 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004984 IEEE80211_HW_AP_LINK_PS |
4985 IEEE80211_HW_AMPDU_AGGREGATION |
4986 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004987
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004988 wl->hw->wiphy->cipher_suites = cipher_suites;
4989 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4990
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004991 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004992 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4993 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004994 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004995 wl->hw->wiphy->max_sched_scan_ssids = 16;
4996 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004997 /*
4998 * Maximum length of elements in scanning probe request templates
4999 * should be the maximum length possible for a template, without
5000 * the IEEE80211 header of the template
5001 */
Eliad Peller154037d2011-08-14 13:17:12 +03005002 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02005003 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005004
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03005005 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
5006 sizeof(struct ieee80211_header);
5007
Eliad Peller1ec23f72011-08-25 14:26:54 +03005008 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
5009
Luciano Coelho4a31c112011-03-21 23:16:14 +02005010 /* make sure all our channels fit in the scanned_ch bitmask */
5011 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
5012 ARRAY_SIZE(wl1271_channels_5ghz) >
5013 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005014 /*
5015 * We keep local copies of the band structs because we need to
5016 * modify them on a per-device basis.
5017 */
5018 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
5019 sizeof(wl1271_band_2ghz));
5020 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
5021 sizeof(wl1271_band_5ghz));
5022
5023 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
5024 &wl->bands[IEEE80211_BAND_2GHZ];
5025 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
5026 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005027
Kalle Valo12bd8942010-03-18 12:26:33 +02005028 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02005029 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02005030
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01005031 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
5032
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02005033 /* the FW answers probe-requests in AP-mode */
5034 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
5035 wl->hw->wiphy->probe_resp_offload =
5036 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
5037 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
5038 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
5039
Felipe Balbia390e852011-10-06 10:07:44 +03005040 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005041
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005042 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02005043 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005044
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005045 wl->hw->max_rx_aggregation_subframes = 8;
5046
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005047 return 0;
5048}
5049
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005050#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005051
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005052static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005053{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005054 struct ieee80211_hw *hw;
5055 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005056 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005057 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005058
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005059 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005060
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005061 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5062 if (!hw) {
5063 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005064 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005065 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005066 }
5067
5068 wl = hw->priv;
5069 memset(wl, 0, sizeof(*wl));
5070
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005071 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005072 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005073
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005074 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005075
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005076 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005077 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005078 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5079
Ido Yariva6208652011-03-01 15:14:41 +02005080 skb_queue_head_init(&wl->deferred_rx_queue);
5081 skb_queue_head_init(&wl->deferred_tx_queue);
5082
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005083 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005084 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005085 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5086 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5087 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005088
Eliad Peller92ef8962011-06-07 12:50:46 +03005089 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5090 if (!wl->freezable_wq) {
5091 ret = -ENOMEM;
5092 goto err_hw;
5093 }
5094
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005095 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005096 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005097 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005098 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005099 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005100 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005101 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005102 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005103 wl->ap_ps_map = 0;
5104 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005105 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005106 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005107 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005108 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005109 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005110 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005111 wl->fwlog_size = 0;
5112 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005113
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005114 /* The system link is always allocated */
5115 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5116
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005117 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005118 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005119 wl->tx_frames[i] = NULL;
5120
5121 spin_lock_init(&wl->wl_lock);
5122
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005123 wl->state = WL1271_STATE_OFF;
5124 mutex_init(&wl->mutex);
5125
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005126 /* Apply default driver configuration. */
5127 wl1271_conf_init(wl);
5128
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005129 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5130 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5131 if (!wl->aggr_buf) {
5132 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005133 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005134 }
5135
Ido Yariv990f5de2011-03-31 10:06:59 +02005136 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5137 if (!wl->dummy_packet) {
5138 ret = -ENOMEM;
5139 goto err_aggr;
5140 }
5141
Ido Yariv95dac04f2011-06-06 14:57:06 +03005142 /* Allocate one page for the FW log */
5143 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5144 if (!wl->fwlog) {
5145 ret = -ENOMEM;
5146 goto err_dummy_packet;
5147 }
5148
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005149 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005150
Ido Yariv990f5de2011-03-31 10:06:59 +02005151err_dummy_packet:
5152 dev_kfree_skb(wl->dummy_packet);
5153
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005154err_aggr:
5155 free_pages((unsigned long)wl->aggr_buf, order);
5156
Eliad Peller92ef8962011-06-07 12:50:46 +03005157err_wq:
5158 destroy_workqueue(wl->freezable_wq);
5159
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005160err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005161 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005162 ieee80211_free_hw(hw);
5163
5164err_hw_alloc:
5165
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005166 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005167}
5168
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005169static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005170{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005171 /* Unblock any fwlog readers */
5172 mutex_lock(&wl->mutex);
5173 wl->fwlog_size = -1;
5174 wake_up_interruptible_all(&wl->fwlog_waitq);
5175 mutex_unlock(&wl->mutex);
5176
Felipe Balbif79f8902011-10-06 13:05:25 +03005177 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005178
Felipe Balbif79f8902011-10-06 13:05:25 +03005179 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005180
Felipe Balbif79f8902011-10-06 13:05:25 +03005181 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005182 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005183 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005184 free_pages((unsigned long)wl->aggr_buf,
5185 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005186
5187 wl1271_debugfs_exit(wl);
5188
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005189 vfree(wl->fw);
5190 wl->fw = NULL;
5191 kfree(wl->nvs);
5192 wl->nvs = NULL;
5193
5194 kfree(wl->fw_status);
5195 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005196 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005197
5198 ieee80211_free_hw(wl->hw);
5199
5200 return 0;
5201}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005202
Felipe Balbia390e852011-10-06 10:07:44 +03005203static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5204{
5205 struct wl1271 *wl = cookie;
5206 unsigned long flags;
5207
5208 wl1271_debug(DEBUG_IRQ, "IRQ");
5209
5210 /* complete the ELP completion */
5211 spin_lock_irqsave(&wl->wl_lock, flags);
5212 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5213 if (wl->elp_compl) {
5214 complete(wl->elp_compl);
5215 wl->elp_compl = NULL;
5216 }
5217
5218 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5219 /* don't enqueue a work right now. mark it as pending */
5220 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5221 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5222 disable_irq_nosync(wl->irq);
5223 pm_wakeup_event(wl->dev, 0);
5224 spin_unlock_irqrestore(&wl->wl_lock, flags);
5225 return IRQ_HANDLED;
5226 }
5227 spin_unlock_irqrestore(&wl->wl_lock, flags);
5228
5229 return IRQ_WAKE_THREAD;
5230}
5231
Felipe Balbice2a2172011-10-05 14:12:55 +03005232static int __devinit wl12xx_probe(struct platform_device *pdev)
5233{
Felipe Balbia390e852011-10-06 10:07:44 +03005234 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5235 struct ieee80211_hw *hw;
5236 struct wl1271 *wl;
5237 unsigned long irqflags;
5238 int ret = -ENODEV;
5239
5240 hw = wl1271_alloc_hw();
5241 if (IS_ERR(hw)) {
5242 wl1271_error("can't allocate hw");
5243 ret = PTR_ERR(hw);
5244 goto out;
5245 }
5246
5247 wl = hw->priv;
5248 wl->irq = platform_get_irq(pdev, 0);
5249 wl->ref_clock = pdata->board_ref_clock;
5250 wl->tcxo_clock = pdata->board_tcxo_clock;
5251 wl->platform_quirks = pdata->platform_quirks;
5252 wl->set_power = pdata->set_power;
5253 wl->dev = &pdev->dev;
5254 wl->if_ops = pdata->ops;
5255
5256 platform_set_drvdata(pdev, wl);
5257
5258 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5259 irqflags = IRQF_TRIGGER_RISING;
5260 else
5261 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5262
5263 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5264 irqflags,
5265 pdev->name, wl);
5266 if (ret < 0) {
5267 wl1271_error("request_irq() failed: %d", ret);
5268 goto out_free_hw;
5269 }
5270
5271 ret = enable_irq_wake(wl->irq);
5272 if (!ret) {
5273 wl->irq_wake_enabled = true;
5274 device_init_wakeup(wl->dev, 1);
5275 if (pdata->pwr_in_suspend)
5276 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5277
5278 }
5279 disable_irq(wl->irq);
5280
5281 ret = wl1271_init_ieee80211(wl);
5282 if (ret)
5283 goto out_irq;
5284
5285 ret = wl1271_register_hw(wl);
5286 if (ret)
5287 goto out_irq;
5288
Felipe Balbif79f8902011-10-06 13:05:25 +03005289 /* Create sysfs file to control bt coex state */
5290 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5291 if (ret < 0) {
5292 wl1271_error("failed to create sysfs file bt_coex_state");
5293 goto out_irq;
5294 }
5295
5296 /* Create sysfs file to get HW PG version */
5297 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5298 if (ret < 0) {
5299 wl1271_error("failed to create sysfs file hw_pg_ver");
5300 goto out_bt_coex_state;
5301 }
5302
5303 /* Create sysfs file for the FW log */
5304 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5305 if (ret < 0) {
5306 wl1271_error("failed to create sysfs file fwlog");
5307 goto out_hw_pg_ver;
5308 }
5309
Felipe Balbice2a2172011-10-05 14:12:55 +03005310 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005311
Felipe Balbif79f8902011-10-06 13:05:25 +03005312out_hw_pg_ver:
5313 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5314
5315out_bt_coex_state:
5316 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5317
Felipe Balbia390e852011-10-06 10:07:44 +03005318out_irq:
5319 free_irq(wl->irq, wl);
5320
5321out_free_hw:
5322 wl1271_free_hw(wl);
5323
5324out:
5325 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005326}
5327
5328static int __devexit wl12xx_remove(struct platform_device *pdev)
5329{
Felipe Balbia390e852011-10-06 10:07:44 +03005330 struct wl1271 *wl = platform_get_drvdata(pdev);
5331
5332 if (wl->irq_wake_enabled) {
5333 device_init_wakeup(wl->dev, 0);
5334 disable_irq_wake(wl->irq);
5335 }
5336 wl1271_unregister_hw(wl);
5337 free_irq(wl->irq, wl);
5338 wl1271_free_hw(wl);
5339
Felipe Balbice2a2172011-10-05 14:12:55 +03005340 return 0;
5341}
5342
5343static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005344 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005345 { } /* Terminating Entry */
5346};
5347MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5348
5349static struct platform_driver wl12xx_driver = {
5350 .probe = wl12xx_probe,
5351 .remove = __devexit_p(wl12xx_remove),
5352 .id_table = wl12xx_id_table,
5353 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005354 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005355 .owner = THIS_MODULE,
5356 }
5357};
5358
5359static int __init wl12xx_init(void)
5360{
5361 return platform_driver_register(&wl12xx_driver);
5362}
5363module_init(wl12xx_init);
5364
5365static void __exit wl12xx_exit(void)
5366{
5367 platform_driver_unregister(&wl12xx_driver);
5368}
5369module_exit(wl12xx_exit);
5370
Guy Eilam491bbd62011-01-12 10:33:29 +01005371u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005372EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005373module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005374MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5375
Ido Yariv95dac04f2011-06-06 14:57:06 +03005376module_param_named(fwlog, fwlog_param, charp, 0);
Luciano Coelho2c882fa2012-02-07 12:37:33 +02005377MODULE_PARM_DESC(fwlog,
Ido Yariv95dac04f2011-06-06 14:57:06 +03005378 "FW logger options: continuous, ondemand, dbgpins or disable");
5379
Eliad Peller2a5bff02011-08-25 18:10:59 +03005380module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5381MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5382
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005383MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005384MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005385MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");