blob: 3a1636b68cd259674728051ccdb9112c99f9440e [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Felipe Balbia390e852011-10-06 10:07:44 +030035#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "wl12xx.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030038#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030039#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000040#include "reg.h"
41#include "io.h"
42#include "event.h"
43#include "tx.h"
44#include "rx.h"
45#include "ps.h"
46#include "init.h"
47#include "debugfs.h"
48#include "cmd.h"
49#include "boot.h"
50#include "testmode.h"
51#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030052
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020053#define WL1271_BOOT_RETRIES 3
54
Juuso Oikarinen8a080482009-10-13 12:47:44 +030055static struct conf_drv_settings default_conf = {
56 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030057 .params = {
58 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
61 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
62 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
64 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
65 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
66 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
68 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
69 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
70 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
71 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
73 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
74 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
75 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
76 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
77 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
78 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
79 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
82 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
83 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
84 /* active scan params */
85 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
86 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
87 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
88 /* passive scan params */
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
91 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
92 /* passive scan in dual antenna params */
93 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
94 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
95 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
96 /* general params */
97 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
98 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
99 [CONF_SG_BEACON_MISS_PERCENT] = 60,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_RXT] = 1200,
102 [CONF_SG_TXT] = 1000,
103 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
104 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
105 [CONF_SG_HV3_MAX_SERVED] = 6,
106 [CONF_SG_PS_POLL_TIMEOUT] = 10,
107 [CONF_SG_UPSD_TIMEOUT] = 10,
108 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
109 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
110 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
111 /* AP params */
112 [CONF_AP_BEACON_MISS_TX] = 3,
113 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
114 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
115 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
116 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
117 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300118 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200119 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300120 },
121 .rx = {
122 .rx_msdu_life_time = 512000,
123 .packet_detection_threshold = 0,
124 .ps_poll_timeout = 15,
125 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300126 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200127 .rx_cca_threshold = 0,
128 .irq_blk_threshold = 0xFFFF,
129 .irq_pkt_threshold = 0,
130 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300131 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
132 },
133 .tx = {
134 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200135 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300136 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300137 .short_retry_limit = 10,
138 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200139 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300140 },
141 .ac_conf_count = 4,
142 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200143 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300144 .ac = CONF_TX_AC_BE,
145 .cw_min = 15,
146 .cw_max = 63,
147 .aifsn = 3,
148 .tx_op_limit = 0,
149 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200150 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300151 .ac = CONF_TX_AC_BK,
152 .cw_min = 15,
153 .cw_max = 63,
154 .aifsn = 7,
155 .tx_op_limit = 0,
156 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200157 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300158 .ac = CONF_TX_AC_VI,
159 .cw_min = 15,
160 .cw_max = 63,
161 .aifsn = CONF_TX_AIFS_PIFS,
162 .tx_op_limit = 3008,
163 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200164 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300165 .ac = CONF_TX_AC_VO,
166 .cw_min = 15,
167 .cw_max = 63,
168 .aifsn = CONF_TX_AIFS_PIFS,
169 .tx_op_limit = 1504,
170 },
171 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300172 .max_tx_retries = 100,
173 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300175 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200176 [CONF_TX_AC_BE] = {
177 .queue_id = CONF_TX_AC_BE,
178 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300179 .tsid = CONF_TX_AC_BE,
180 .ps_scheme = CONF_PS_SCHEME_LEGACY,
181 .ack_policy = CONF_ACK_POLICY_LEGACY,
182 .apsd_conf = {0, 0},
183 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200184 [CONF_TX_AC_BK] = {
185 .queue_id = CONF_TX_AC_BK,
186 .channel_type = CONF_CHANNEL_TYPE_EDCF,
187 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300188 .ps_scheme = CONF_PS_SCHEME_LEGACY,
189 .ack_policy = CONF_ACK_POLICY_LEGACY,
190 .apsd_conf = {0, 0},
191 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200192 [CONF_TX_AC_VI] = {
193 .queue_id = CONF_TX_AC_VI,
194 .channel_type = CONF_CHANNEL_TYPE_EDCF,
195 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .ps_scheme = CONF_PS_SCHEME_LEGACY,
197 .ack_policy = CONF_ACK_POLICY_LEGACY,
198 .apsd_conf = {0, 0},
199 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200200 [CONF_TX_AC_VO] = {
201 .queue_id = CONF_TX_AC_VO,
202 .channel_type = CONF_CHANNEL_TYPE_EDCF,
203 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300204 .ps_scheme = CONF_PS_SCHEME_LEGACY,
205 .ack_policy = CONF_ACK_POLICY_LEGACY,
206 .apsd_conf = {0, 0},
207 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300208 },
209 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200210 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300211 .tx_compl_threshold = 4,
212 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
213 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200214 .tmpl_short_retry_limit = 10,
215 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300216 },
217 .conn = {
218 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300219 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300221 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300222 .bcn_filt_ie = {
223 [0] = {
224 .ie = WLAN_EID_CHANNEL_SWITCH,
225 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300226 },
227 [1] = {
228 .ie = WLAN_EID_HT_INFORMATION,
229 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
230 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200232 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 .bss_lose_timeout = 100,
234 .beacon_rx_timeout = 10000,
235 .broadcast_timeout = 20000,
236 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300237 .ps_poll_threshold = 10,
238 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300239 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e02011-03-14 18:53:10 +0200240 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300241 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300242 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200243 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300244 .keep_alive_interval = 55000,
245 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300246 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200247 .itrim = {
248 .enable = false,
249 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200250 },
251 .pm_config = {
252 .host_clk_settling_time = 5000,
253 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 },
255 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300256 .trigger_pacing = 1,
257 .avg_weight_rssi_beacon = 20,
258 .avg_weight_rssi_data = 10,
259 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100260 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200261 },
262 .scan = {
263 .min_dwell_time_active = 7500,
264 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100265 .min_dwell_time_passive = 100000,
266 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200267 .num_probe_reqs = 2,
268 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300269 .sched_scan = {
270 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300271 .min_dwell_time_active = 30,
272 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300274 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300275 .num_probe_reqs = 2,
276 .rssi_threshold = -90,
277 .snr_threshold = 0,
278 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200279 .rf = {
280 .tx_per_channel_power_compensation_2 = {
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 },
283 .tx_per_channel_power_compensation_5 = {
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 },
288 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300290 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100291 .tx_ba_win_size = 64,
292 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300293 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100294 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200295 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200296 .num_stations = 1,
297 .ssid_profiles = 1,
298 .rx_block_num = 70,
299 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300300 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200301 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200302 .min_req_rx_blocks = 22,
303 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200304 },
305 .mem_wl128x = {
306 .num_stations = 1,
307 .ssid_profiles = 1,
308 .rx_block_num = 40,
309 .tx_min_block_num = 40,
310 .dynamic_memory = 1,
311 .min_req_tx_blocks = 45,
312 .min_req_rx_blocks = 22,
313 .tx_min = 27,
314 },
Shahar Leviff868432011-04-11 15:41:46 +0300315 .fm_coex = {
316 .enable = true,
317 .swallow_period = 5,
318 .n_divider_fref_set_1 = 0xff, /* default */
319 .n_divider_fref_set_2 = 12,
320 .m_divider_fref_set_1 = 148,
321 .m_divider_fref_set_2 = 0xffff, /* default */
322 .coex_pll_stabilization_time = 0xffffffff, /* default */
323 .ldo_stabilization_time = 0xffff, /* default */
324 .fm_disturbed_band_margin = 0xff, /* default */
325 .swallow_clk_diff = 0xff, /* default */
326 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300327 .rx_streaming = {
328 .duration = 150,
329 .queues = 0x1,
330 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300331 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300332 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300333 .fwlog = {
334 .mode = WL12XX_FWLOG_ON_DEMAND,
335 .mem_blocks = 2,
336 .severity = 0,
337 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
338 .output = WL12XX_FWLOG_OUTPUT_HOST,
339 .threshold = 0,
340 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300341 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300342 .rate = {
343 .rate_retry_score = 32000,
344 .per_add = 8192,
345 .per_th1 = 2048,
346 .per_th2 = 4096,
347 .max_per = 8100,
348 .inverse_curiosity_factor = 5,
349 .tx_fail_low_th = 4,
350 .tx_fail_high_th = 10,
351 .per_alpha_shift = 4,
352 .per_add_shift = 13,
353 .per_beta1_shift = 10,
354 .per_beta2_shift = 8,
355 .rate_check_up = 2,
356 .rate_check_down = 12,
357 .rate_retry_policy = {
358 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00,
361 },
362 },
Eliad Peller94877752011-08-28 15:11:56 +0300363 .hangover = {
364 .recover_time = 0,
365 .hangover_period = 20,
366 .dynamic_mode = 1,
367 .early_termination_mode = 1,
368 .max_period = 20,
369 .min_period = 1,
370 .increase_delta = 1,
371 .decrease_delta = 2,
372 .quiet_time = 4,
373 .increase_time = 1,
374 .window_size = 16,
375 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300376};
377
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300379static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300380
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300381static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200382 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300383 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200384static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200385static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200386
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200387static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300388static LIST_HEAD(wl_list);
389
Eliad Pellerba8447f2011-10-10 10:13:00 +0200390static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
391 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300392{
393 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200394
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300395 if (operstate != IF_OPER_UP)
396 return 0;
397
Eliad Peller8181aec2011-10-10 10:13:04 +0200398 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300399 return 0;
400
Eliad Peller154da672011-10-05 11:55:53 +0200401 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300402 if (ret < 0)
403 return ret;
404
Eliad Peller0603d892011-10-05 11:55:51 +0200405 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300406
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300407 wl1271_info("Association completed.");
408 return 0;
409}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300410static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
411 void *arg)
412{
413 struct net_device *dev = arg;
414 struct wireless_dev *wdev;
415 struct wiphy *wiphy;
416 struct ieee80211_hw *hw;
417 struct wl1271 *wl;
418 struct wl1271 *wl_temp;
Eliad Pellerba8447f2011-10-10 10:13:00 +0200419 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300420 int ret = 0;
421
422 /* Check that this notification is for us. */
423 if (what != NETDEV_CHANGE)
424 return NOTIFY_DONE;
425
426 wdev = dev->ieee80211_ptr;
427 if (wdev == NULL)
428 return NOTIFY_DONE;
429
430 wiphy = wdev->wiphy;
431 if (wiphy == NULL)
432 return NOTIFY_DONE;
433
434 hw = wiphy_priv(wiphy);
435 if (hw == NULL)
436 return NOTIFY_DONE;
437
438 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200439 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300440 list_for_each_entry(wl, &wl_list, list) {
441 if (wl == wl_temp)
442 break;
443 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200444 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300445 if (wl != wl_temp)
446 return NOTIFY_DONE;
447
448 mutex_lock(&wl->mutex);
449
450 if (wl->state == WL1271_STATE_OFF)
451 goto out;
452
Eliad Peller6ab70912011-12-18 20:25:45 +0200453 if (dev->operstate != IF_OPER_UP)
454 goto out;
455 /*
456 * The correct behavior should be just getting the appropriate wlvif
457 * from the given dev, but currently we don't have a mac80211
458 * interface for it.
459 */
Eliad Pellerba8447f2011-10-10 10:13:00 +0200460 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller6ab70912011-12-18 20:25:45 +0200461 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
462
Eliad Pellerba8447f2011-10-10 10:13:00 +0200463 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
464 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300465
Eliad Pellerba8447f2011-10-10 10:13:00 +0200466 ret = wl1271_ps_elp_wakeup(wl);
467 if (ret < 0)
468 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300469
Eliad Peller6ab70912011-12-18 20:25:45 +0200470 wl1271_check_operstate(wl, wlvif,
471 ieee80211_get_operstate(vif));
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300472
Eliad Pellerba8447f2011-10-10 10:13:00 +0200473 wl1271_ps_elp_sleep(wl);
474 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300475out:
476 mutex_unlock(&wl->mutex);
477
478 return NOTIFY_OK;
479}
480
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100481static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200482 struct regulatory_request *request)
483{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100484 struct ieee80211_supported_band *band;
485 struct ieee80211_channel *ch;
486 int i;
487
488 band = wiphy->bands[IEEE80211_BAND_5GHZ];
489 for (i = 0; i < band->n_channels; i++) {
490 ch = &band->channels[i];
491 if (ch->flags & IEEE80211_CHAN_DISABLED)
492 continue;
493
494 if (ch->flags & IEEE80211_CHAN_RADAR)
495 ch->flags |= IEEE80211_CHAN_NO_IBSS |
496 IEEE80211_CHAN_PASSIVE_SCAN;
497
498 }
499
500 return 0;
501}
502
Eliad Peller9eb599e2011-10-10 10:12:59 +0200503static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
504 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300505{
506 int ret = 0;
507
508 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200509 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300510 if (ret < 0)
511 goto out;
512
513 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200514 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300515 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200516 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300517out:
518 return ret;
519}
520
521/*
522 * this function is being called when the rx_streaming interval
523 * has beed changed or rx_streaming should be disabled
524 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200525int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300526{
527 int ret = 0;
528 int period = wl->conf.rx_streaming.interval;
529
530 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200531 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300532 goto out;
533
534 /* reconfigure/disable according to new streaming_period */
535 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200536 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300537 (wl->conf.rx_streaming.always ||
538 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200539 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300540 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200541 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300542 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200543 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300544 }
545out:
546 return ret;
547}
548
549static void wl1271_rx_streaming_enable_work(struct work_struct *work)
550{
551 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200552 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
553 rx_streaming_enable_work);
554 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300555
556 mutex_lock(&wl->mutex);
557
Eliad Peller0744bdb2011-10-10 10:13:05 +0200558 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200559 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300560 (!wl->conf.rx_streaming.always &&
561 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
562 goto out;
563
564 if (!wl->conf.rx_streaming.interval)
565 goto out;
566
567 ret = wl1271_ps_elp_wakeup(wl);
568 if (ret < 0)
569 goto out;
570
Eliad Peller9eb599e2011-10-10 10:12:59 +0200571 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300572 if (ret < 0)
573 goto out_sleep;
574
575 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200576 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300577 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
578
579out_sleep:
580 wl1271_ps_elp_sleep(wl);
581out:
582 mutex_unlock(&wl->mutex);
583}
584
585static void wl1271_rx_streaming_disable_work(struct work_struct *work)
586{
587 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200588 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
589 rx_streaming_disable_work);
590 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300591
592 mutex_lock(&wl->mutex);
593
Eliad Peller0744bdb2011-10-10 10:13:05 +0200594 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300595 goto out;
596
597 ret = wl1271_ps_elp_wakeup(wl);
598 if (ret < 0)
599 goto out;
600
Eliad Peller9eb599e2011-10-10 10:12:59 +0200601 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300602 if (ret)
603 goto out_sleep;
604
605out_sleep:
606 wl1271_ps_elp_sleep(wl);
607out:
608 mutex_unlock(&wl->mutex);
609}
610
611static void wl1271_rx_streaming_timer(unsigned long data)
612{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200613 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
614 struct wl1271 *wl = wlvif->wl;
615 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300616}
617
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300618static void wl1271_conf_init(struct wl1271 *wl)
619{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300620
621 /*
622 * This function applies the default configuration to the driver. This
623 * function is invoked upon driver load (spi probe.)
624 *
625 * The configuration is stored in a run-time structure in order to
626 * facilitate for run-time adjustment of any of the parameters. Making
627 * changes to the configuration structure will apply the new values on
628 * the next interface up (wl1271_op_start.)
629 */
630
631 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300632 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300633
Ido Yariv95dac04f2011-06-06 14:57:06 +0300634 /* Adjust settings according to optional module parameters */
635 if (fwlog_param) {
636 if (!strcmp(fwlog_param, "continuous")) {
637 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
638 } else if (!strcmp(fwlog_param, "ondemand")) {
639 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
640 } else if (!strcmp(fwlog_param, "dbgpins")) {
641 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
642 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
643 } else if (!strcmp(fwlog_param, "disable")) {
644 wl->conf.fwlog.mem_blocks = 0;
645 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
646 } else {
647 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
648 }
649 }
650}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300651
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300652static int wl1271_plt_init(struct wl1271 *wl)
653{
Eliad Peller188e7f52011-12-06 12:15:06 +0200654 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300655
Shahar Levi49d750ca2011-03-06 16:32:09 +0200656 if (wl->chip.id == CHIP_ID_1283_PG20)
657 ret = wl128x_cmd_general_parms(wl);
658 else
659 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200660 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200661 return ret;
662
Shahar Levi49d750ca2011-03-06 16:32:09 +0200663 if (wl->chip.id == CHIP_ID_1283_PG20)
664 ret = wl128x_cmd_radio_parms(wl);
665 else
666 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200667 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200668 return ret;
669
Shahar Levi49d750ca2011-03-06 16:32:09 +0200670 if (wl->chip.id != CHIP_ID_1283_PG20) {
671 ret = wl1271_cmd_ext_radio_parms(wl);
672 if (ret < 0)
673 return ret;
674 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200675 if (ret < 0)
676 return ret;
677
Shahar Levi48a61472011-03-06 16:32:08 +0200678 /* Chip-specific initializations */
679 ret = wl1271_chip_specific_init(wl);
680 if (ret < 0)
681 return ret;
682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 ret = wl1271_acx_init_mem_config(wl);
684 if (ret < 0)
685 return ret;
686
Eliad Peller7f0979882011-08-14 13:17:06 +0300687 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600688 if (ret < 0)
689 goto out_free_memmap;
690
Luciano Coelho12419cc2010-02-18 13:25:44 +0200691 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200692 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300693 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200694 goto out_free_memmap;
695
696 /* Configure for CAM power saving (ie. always active) */
697 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
698 if (ret < 0)
699 goto out_free_memmap;
700
701 /* configure PM */
702 ret = wl1271_acx_pm_config(wl);
703 if (ret < 0)
704 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300705
706 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200707
708 out_free_memmap:
709 kfree(wl->target_mem_map);
710 wl->target_mem_map = NULL;
711
712 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713}
714
Eliad Peller6e8cd332011-10-10 10:13:13 +0200715static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
716 struct wl12xx_vif *wlvif,
717 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200718{
Arik Nemtsovda032092011-08-25 12:43:15 +0300719 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200720
Arik Nemtsovb622d992011-02-23 00:22:31 +0200721 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300722 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200723
724 /*
725 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300726 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200727 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300728 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200729 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200730
Arik Nemtsovda032092011-08-25 12:43:15 +0300731 /*
732 * Start high-level PS if the STA is asleep with enough blocks in FW.
733 * Make an exception if this is the only connected station. In this
734 * case FW-memory congestion is not a problem.
735 */
736 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200737 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200738}
739
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300740static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200741 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300742 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200743{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200744 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200745 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300746 u8 hlid, cnt;
747
748 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200749
750 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
751 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
752 wl1271_debug(DEBUG_PSM,
753 "link ps prev 0x%x cur 0x%x changed 0x%x",
754 wl->ap_fw_ps_map, cur_fw_ps_map,
755 wl->ap_fw_ps_map ^ cur_fw_ps_map);
756
757 wl->ap_fw_ps_map = cur_fw_ps_map;
758 }
759
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200760 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
761 lnk = &wl->links[hlid];
762 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200763
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200764 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
765 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200766
Eliad Peller6e8cd332011-10-10 10:13:13 +0200767 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
768 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200769 }
770}
771
Eliad Peller4d56ad92011-08-14 13:17:05 +0300772static void wl12xx_fw_status(struct wl1271 *wl,
773 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300774{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200775 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200776 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200777 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300778 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300779 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300780
Eliad Peller4d56ad92011-08-14 13:17:05 +0300781 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200782
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300783 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
784 "drv_rx_counter = %d, tx_results_counter = %d)",
785 status->intr,
786 status->fw_rx_counter,
787 status->drv_rx_counter,
788 status->tx_results_counter);
789
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300790 for (i = 0; i < NUM_TX_QUEUES; i++) {
791 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300792 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300793 (status->tx_released_pkts[i] -
794 wl->tx_pkts_freed[i]) & 0xff;
795
796 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
797 }
798
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300799 /* prevent wrap-around in total blocks counter */
800 if (likely(wl->tx_blocks_freed <=
801 le32_to_cpu(status->total_released_blks)))
802 freed_blocks = le32_to_cpu(status->total_released_blks) -
803 wl->tx_blocks_freed;
804 else
805 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
806 le32_to_cpu(status->total_released_blks);
807
Eliad Peller4d56ad92011-08-14 13:17:05 +0300808 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200809
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300810 wl->tx_allocated_blocks -= freed_blocks;
811
Eliad Peller4d56ad92011-08-14 13:17:05 +0300812 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200813
Eliad Peller4d56ad92011-08-14 13:17:05 +0300814 /*
815 * The FW might change the total number of TX memblocks before
816 * we get a notification about blocks being released. Thus, the
817 * available blocks calculation might yield a temporary result
818 * which is lower than the actual available blocks. Keeping in
819 * mind that only blocks that were allocated can be moved from
820 * TX to RX, tx_blocks_available should never decrease here.
821 */
822 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
823 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300824
Ido Yariva5225502010-10-12 14:49:10 +0200825 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200826 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200827 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828
Eliad Peller4d56ad92011-08-14 13:17:05 +0300829 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200830 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200831 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200832 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300833
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200835 getnstimeofday(&ts);
836 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
837 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300838}
839
Ido Yariva6208652011-03-01 15:14:41 +0200840static void wl1271_flush_deferred_work(struct wl1271 *wl)
841{
842 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200843
Ido Yariva6208652011-03-01 15:14:41 +0200844 /* Pass all received frames to the network stack */
845 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
846 ieee80211_rx_ni(wl->hw, skb);
847
848 /* Return sent skbs to the network stack */
849 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300850 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200851}
852
853static void wl1271_netstack_work(struct work_struct *work)
854{
855 struct wl1271 *wl =
856 container_of(work, struct wl1271, netstack_work);
857
858 do {
859 wl1271_flush_deferred_work(wl);
860 } while (skb_queue_len(&wl->deferred_rx_queue));
861}
862
863#define WL1271_IRQ_MAX_LOOPS 256
864
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300865static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300866{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300867 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300868 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200869 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200870 struct wl1271 *wl = (struct wl1271 *)cookie;
871 bool done = false;
872 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200873 unsigned long flags;
874
875 /* TX might be handled here, avoid redundant work */
876 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
877 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878
Ido Yariv341b7cd2011-03-31 10:07:01 +0200879 /*
880 * In case edge triggered interrupt must be used, we cannot iterate
881 * more than once without introducing race conditions with the hardirq.
882 */
883 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
884 loopcount = 1;
885
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300886 mutex_lock(&wl->mutex);
887
888 wl1271_debug(DEBUG_IRQ, "IRQ work");
889
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200890 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300891 goto out;
892
Ido Yariva6208652011-03-01 15:14:41 +0200893 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300894 if (ret < 0)
895 goto out;
896
Ido Yariva6208652011-03-01 15:14:41 +0200897 while (!done && loopcount--) {
898 /*
899 * In order to avoid a race with the hardirq, clear the flag
900 * before acknowledging the chip. Since the mutex is held,
901 * wl1271_ps_elp_wakeup cannot be called concurrently.
902 */
903 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
904 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200905
Eliad Peller4d56ad92011-08-14 13:17:05 +0300906 wl12xx_fw_status(wl, wl->fw_status);
907 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200908 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200909 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200910 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200911 continue;
912 }
913
Eliad Pellerccc83b02010-10-27 14:09:57 +0200914 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
915 wl1271_error("watchdog interrupt received! "
916 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300917 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200918
919 /* restarting the chip. ignore any other interrupt. */
920 goto out;
921 }
922
Ido Yariva6208652011-03-01 15:14:41 +0200923 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200924 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
925
Eliad Peller4d56ad92011-08-14 13:17:05 +0300926 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200927
Ido Yariva5225502010-10-12 14:49:10 +0200928 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200929 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200930 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300931 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200932 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200933 /*
934 * In order to avoid starvation of the TX path,
935 * call the work function directly.
936 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200937 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200938 } else {
939 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200940 }
941
Ido Yariv8aad2462011-03-01 15:14:38 +0200942 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300943 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200944 (wl->tx_results_count & 0xff))
945 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200946
947 /* Make sure the deferred queues don't get too long */
948 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
949 skb_queue_len(&wl->deferred_rx_queue);
950 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
951 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200952 }
953
954 if (intr & WL1271_ACX_INTR_EVENT_A) {
955 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
956 wl1271_event_handle(wl, 0);
957 }
958
959 if (intr & WL1271_ACX_INTR_EVENT_B) {
960 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
961 wl1271_event_handle(wl, 1);
962 }
963
964 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
965 wl1271_debug(DEBUG_IRQ,
966 "WL1271_ACX_INTR_INIT_COMPLETE");
967
968 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
969 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970 }
971
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972 wl1271_ps_elp_sleep(wl);
973
974out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200975 spin_lock_irqsave(&wl->wl_lock, flags);
976 /* In case TX was not handled here, queue TX work */
977 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
978 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300979 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200980 ieee80211_queue_work(wl->hw, &wl->tx_work);
981 spin_unlock_irqrestore(&wl->wl_lock, flags);
982
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200984
985 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300986}
987
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988static int wl1271_fetch_firmware(struct wl1271 *wl)
989{
990 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200991 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300992 int ret;
993
Arik Nemtsovc302b2c2011-08-17 10:45:48 +0300994 if (wl->chip.id == CHIP_ID_1283_PG20)
995 fw_name = WL128X_FW_NAME;
996 else
997 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200998
999 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1000
Felipe Balbia390e852011-10-06 10:07:44 +03001001 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001002
1003 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001004 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001005 return ret;
1006 }
1007
1008 if (fw->size % 4) {
1009 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1010 fw->size);
1011 ret = -EILSEQ;
1012 goto out;
1013 }
1014
Arik Nemtsov166d5042010-10-16 21:44:57 +02001015 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001017 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018
1019 if (!wl->fw) {
1020 wl1271_error("could not allocate memory for the firmware");
1021 ret = -ENOMEM;
1022 goto out;
1023 }
1024
1025 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026 ret = 0;
1027
1028out:
1029 release_firmware(fw);
1030
1031 return ret;
1032}
1033
1034static int wl1271_fetch_nvs(struct wl1271 *wl)
1035{
1036 const struct firmware *fw;
1037 int ret;
1038
Felipe Balbia390e852011-10-06 10:07:44 +03001039 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040
1041 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001042 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
1043 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001044 return ret;
1045 }
1046
Shahar Levibc765bf2011-03-06 16:32:10 +02001047 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048
1049 if (!wl->nvs) {
1050 wl1271_error("could not allocate memory for the nvs file");
1051 ret = -ENOMEM;
1052 goto out;
1053 }
1054
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001055 wl->nvs_len = fw->size;
1056
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057out:
1058 release_firmware(fw);
1059
1060 return ret;
1061}
1062
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001063void wl12xx_queue_recovery_work(struct wl1271 *wl)
1064{
1065 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1066 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1067}
1068
Ido Yariv95dac04f2011-06-06 14:57:06 +03001069size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1070{
1071 size_t len = 0;
1072
1073 /* The FW log is a length-value list, find where the log end */
1074 while (len < maxlen) {
1075 if (memblock[len] == 0)
1076 break;
1077 if (len + memblock[len] + 1 > maxlen)
1078 break;
1079 len += memblock[len] + 1;
1080 }
1081
1082 /* Make sure we have enough room */
1083 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1084
1085 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1086 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1087 wl->fwlog_size += len;
1088
1089 return len;
1090}
1091
1092static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1093{
1094 u32 addr;
1095 u32 first_addr;
1096 u8 *block;
1097
1098 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1099 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1100 (wl->conf.fwlog.mem_blocks == 0))
1101 return;
1102
1103 wl1271_info("Reading FW panic log");
1104
1105 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1106 if (!block)
1107 return;
1108
1109 /*
1110 * Make sure the chip is awake and the logger isn't active.
1111 * This might fail if the firmware hanged.
1112 */
1113 if (!wl1271_ps_elp_wakeup(wl))
1114 wl12xx_cmd_stop_fwlog(wl);
1115
1116 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001117 wl12xx_fw_status(wl, wl->fw_status);
1118 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001119 if (!first_addr)
1120 goto out;
1121
1122 /* Traverse the memory blocks linked list */
1123 addr = first_addr;
1124 do {
1125 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1126 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1127 false);
1128
1129 /*
1130 * Memory blocks are linked to one another. The first 4 bytes
1131 * of each memory block hold the hardware address of the next
1132 * one. The last memory block points to the first one.
1133 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001134 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001135 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1136 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1137 break;
1138 } while (addr && (addr != first_addr));
1139
1140 wake_up_interruptible(&wl->fwlog_waitq);
1141
1142out:
1143 kfree(block);
1144}
1145
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001146static void wl1271_recovery_work(struct work_struct *work)
1147{
1148 struct wl1271 *wl =
1149 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001150 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001151 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001152
1153 mutex_lock(&wl->mutex);
1154
1155 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001156 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001157
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001158 /* Avoid a recursive recovery */
1159 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1160
Ido Yariv95dac04f2011-06-06 14:57:06 +03001161 wl12xx_read_fwlog_panic(wl);
1162
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001163 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1164 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001165
Eliad Peller2a5bff02011-08-25 18:10:59 +03001166 BUG_ON(bug_on_recovery);
1167
Oz Krakowskib992c682011-06-26 10:36:02 +03001168 /*
1169 * Advance security sequence number to overcome potential progress
1170 * in the firmware during recovery. This doens't hurt if the network is
1171 * not encrypted.
1172 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001173 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001174 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001175 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001176 wlvif->tx_security_seq +=
1177 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1178 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001179
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001180 /* Prevent spurious TX during FW restart */
1181 ieee80211_stop_queues(wl->hw);
1182
Luciano Coelho33c2c062011-05-10 14:46:02 +03001183 if (wl->sched_scanning) {
1184 ieee80211_sched_scan_stopped(wl->hw);
1185 wl->sched_scanning = false;
1186 }
1187
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001188 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001189 while (!list_empty(&wl->wlvif_list)) {
1190 wlvif = list_first_entry(&wl->wlvif_list,
1191 struct wl12xx_vif, list);
1192 vif = wl12xx_wlvif_to_vif(wlvif);
1193 __wl1271_op_remove_interface(wl, vif, false);
1194 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001195 mutex_unlock(&wl->mutex);
1196 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001197
1198 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1199
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001200 ieee80211_restart_hw(wl->hw);
1201
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001202 /*
1203 * Its safe to enable TX now - the queues are stopped after a request
1204 * to restart the HW.
1205 */
1206 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001207 return;
1208out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001209 mutex_unlock(&wl->mutex);
1210}
1211
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001212static void wl1271_fw_wakeup(struct wl1271 *wl)
1213{
1214 u32 elp_reg;
1215
1216 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001217 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218}
1219
1220static int wl1271_setup(struct wl1271 *wl)
1221{
1222 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1223 if (!wl->fw_status)
1224 return -ENOMEM;
1225
1226 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1227 if (!wl->tx_res_if) {
1228 kfree(wl->fw_status);
1229 return -ENOMEM;
1230 }
1231
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001232 return 0;
1233}
1234
1235static int wl1271_chip_wakeup(struct wl1271 *wl)
1236{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001237 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001238 int ret = 0;
1239
Juuso Oikarinen01ac17ec2009-12-11 15:41:02 +02001240 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001241 ret = wl1271_power_on(wl);
1242 if (ret < 0)
1243 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001244 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001245 wl1271_io_reset(wl);
1246 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247
1248 /* We don't need a real memory partition here, because we only want
1249 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001250 memset(&partition, 0, sizeof(partition));
1251 partition.reg.start = REGISTERS_BASE;
1252 partition.reg.size = REGISTERS_DOWN_SIZE;
1253 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254
1255 /* ELP module wake up */
1256 wl1271_fw_wakeup(wl);
1257
1258 /* whal_FwCtrl_BootSm() */
1259
1260 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001261 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001262
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001263 /*
1264 * For wl127x based devices we could use the default block
1265 * size (512 bytes), but due to a bug in the sdio driver, we
1266 * need to set it explicitly after the chip is powered on. To
1267 * simplify the code and since the performance impact is
1268 * negligible, we use the same block size for all different
1269 * chip types.
1270 */
1271 if (!wl1271_set_block_size(wl))
1272 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273
1274 switch (wl->chip.id) {
1275 case CHIP_ID_1271_PG10:
1276 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1277 wl->chip.id);
1278
1279 ret = wl1271_setup(wl);
1280 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001281 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001282 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001284
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 case CHIP_ID_1271_PG20:
1286 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1287 wl->chip.id);
1288
1289 ret = wl1271_setup(wl);
1290 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001291 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001292 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001293 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001294
Shahar Levi0830cee2011-03-06 16:32:20 +02001295 case CHIP_ID_1283_PG20:
1296 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1297 wl->chip.id);
1298
1299 ret = wl1271_setup(wl);
1300 if (ret < 0)
1301 goto out;
1302 break;
1303 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001304 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001305 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001307 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001308 }
1309
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001310 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001311 ret = wl1271_fetch_firmware(wl);
1312 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001313 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314 }
1315
1316 /* No NVS from netlink, try to get it from the filesystem */
1317 if (wl->nvs == NULL) {
1318 ret = wl1271_fetch_nvs(wl);
1319 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001320 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321 }
1322
1323out:
1324 return ret;
1325}
1326
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327int wl1271_plt_start(struct wl1271 *wl)
1328{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001329 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001330 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331 int ret;
1332
1333 mutex_lock(&wl->mutex);
1334
1335 wl1271_notice("power up");
1336
1337 if (wl->state != WL1271_STATE_OFF) {
1338 wl1271_error("cannot go into PLT state because not "
1339 "in off state: %d", wl->state);
1340 ret = -EBUSY;
1341 goto out;
1342 }
1343
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001344 while (retries) {
1345 retries--;
1346 ret = wl1271_chip_wakeup(wl);
1347 if (ret < 0)
1348 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001349
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001350 ret = wl1271_boot(wl);
1351 if (ret < 0)
1352 goto power_off;
1353
1354 ret = wl1271_plt_init(wl);
1355 if (ret < 0)
1356 goto irq_disable;
1357
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001358 wl->state = WL1271_STATE_PLT;
1359 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001360 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001361
Gery Kahn6f07b722011-07-18 14:21:49 +03001362 /* update hw/fw version info in wiphy struct */
1363 wiphy->hw_version = wl->chip.id;
1364 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1365 sizeof(wiphy->fw_version));
1366
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367 goto out;
1368
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001369irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001370 mutex_unlock(&wl->mutex);
1371 /* Unlocking the mutex in the middle of handling is
1372 inherently unsafe. In this case we deem it safe to do,
1373 because we need to let any possibly pending IRQ out of
1374 the system (and while we are WL1271_STATE_OFF the IRQ
1375 work function will not do anything.) Also, any other
1376 possible concurrent operations will fail due to the
1377 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001378 wl1271_disable_interrupts(wl);
1379 wl1271_flush_deferred_work(wl);
1380 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001381 mutex_lock(&wl->mutex);
1382power_off:
1383 wl1271_power_off(wl);
1384 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001386 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1387 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001388out:
1389 mutex_unlock(&wl->mutex);
1390
1391 return ret;
1392}
1393
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 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001424 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001425
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001426 mutex_unlock(&wl->mutex);
Ido Yarivf3df1332012-01-11 09:42:39 +02001427
Ido Yariva6208652011-03-01 15:14:41 +02001428 wl1271_flush_deferred_work(wl);
1429 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001430 cancel_work_sync(&wl->recovery_work);
Ido Yariva4549692012-01-11 09:42:40 +02001431
1432 mutex_lock(&wl->mutex);
1433 wl1271_power_off(wl);
1434 mutex_unlock(&wl->mutex);
1435
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001436out:
1437 return ret;
1438}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001439
Johannes Berg7bb45682011-02-24 14:42:06 +01001440static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441{
1442 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001443 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1444 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001445 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001446 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001447 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001448 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001449
Eliad Peller0f168012011-10-11 13:52:25 +02001450 if (vif)
1451 wlvif = wl12xx_vif_to_data(vif);
1452
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001453 mapping = skb_get_queue_mapping(skb);
1454 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001455
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001456 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001457
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001458 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001459
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001460 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001461 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001462 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001463 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001464 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001465 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001466 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001467
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001468 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1469 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1470
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001471 wl->tx_queue_count[q]++;
1472
1473 /*
1474 * The workqueue is slow to process the tx_queue and we need stop
1475 * the queue here, otherwise the queue will get too long.
1476 */
1477 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1478 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1479 ieee80211_stop_queue(wl->hw, mapping);
1480 set_bit(q, &wl->stopped_queues_map);
1481 }
1482
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001483 /*
1484 * The chip specific setup must run before the first TX packet -
1485 * before that, the tx_work will not be initialized!
1486 */
1487
Ido Yarivb07d4032011-03-01 15:14:43 +02001488 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1489 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001490 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001491
Arik Nemtsov04216da2011-08-14 13:17:38 +03001492out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001493 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001494}
1495
Shahar Leviae47c452011-03-06 16:32:14 +02001496int wl1271_tx_dummy_packet(struct wl1271 *wl)
1497{
Ido Yariv990f5de2011-03-31 10:06:59 +02001498 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001499 int q;
1500
1501 /* no need to queue a new dummy packet if one is already pending */
1502 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1503 return 0;
1504
1505 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001506
Ido Yariv990f5de2011-03-31 10:06:59 +02001507 spin_lock_irqsave(&wl->wl_lock, flags);
1508 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001509 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001510 spin_unlock_irqrestore(&wl->wl_lock, flags);
1511
1512 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1513 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001514 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001515
1516 /*
1517 * If the FW TX is busy, TX work will be scheduled by the threaded
1518 * interrupt handler function
1519 */
1520 return 0;
1521}
1522
1523/*
1524 * The size of the dummy packet should be at least 1400 bytes. However, in
1525 * order to minimize the number of bus transactions, aligning it to 512 bytes
1526 * boundaries could be beneficial, performance wise
1527 */
1528#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1529
Luciano Coelhocf27d862011-04-01 21:08:23 +03001530static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001531{
1532 struct sk_buff *skb;
1533 struct ieee80211_hdr_3addr *hdr;
1534 unsigned int dummy_packet_size;
1535
1536 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1537 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1538
1539 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001540 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001541 wl1271_warning("Failed to allocate a dummy packet skb");
1542 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001543 }
1544
1545 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1546
1547 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1548 memset(hdr, 0, sizeof(*hdr));
1549 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001550 IEEE80211_STYPE_NULLFUNC |
1551 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001552
Ido Yariv990f5de2011-03-31 10:06:59 +02001553 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001554
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001555 /* Dummy packets require the TID to be management */
1556 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001557
1558 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001559 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001560 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001561
Ido Yariv990f5de2011-03-31 10:06:59 +02001562 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001563}
1564
Ido Yariv990f5de2011-03-31 10:06:59 +02001565
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001566static struct notifier_block wl1271_dev_notifier = {
1567 .notifier_call = wl1271_dev_notify,
1568};
1569
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001570#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001571static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1572 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001573{
Eliad Pellere85d1622011-06-27 13:06:43 +03001574 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001575
Eliad Peller94390642011-05-13 11:57:13 +03001576 mutex_lock(&wl->mutex);
1577
Eliad Pellerba8447f2011-10-10 10:13:00 +02001578 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001579 goto out_unlock;
1580
Eliad Peller94390642011-05-13 11:57:13 +03001581 ret = wl1271_ps_elp_wakeup(wl);
1582 if (ret < 0)
1583 goto out_unlock;
1584
1585 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001586 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001587 DECLARE_COMPLETION_ONSTACK(compl);
1588
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001589 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001590 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001591 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001592 if (ret < 0)
1593 goto out_sleep;
1594
1595 /* we must unlock here so we will be able to get events */
1596 wl1271_ps_elp_sleep(wl);
1597 mutex_unlock(&wl->mutex);
1598
1599 ret = wait_for_completion_timeout(
1600 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
Pontus Fuchsef187062011-12-14 14:32:23 +01001601
1602 mutex_lock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001603 if (ret <= 0) {
1604 wl1271_warning("couldn't enter ps mode!");
1605 ret = -EBUSY;
Pontus Fuchsef187062011-12-14 14:32:23 +01001606 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001607 }
1608
Eliad Peller94390642011-05-13 11:57:13 +03001609 ret = wl1271_ps_elp_wakeup(wl);
1610 if (ret < 0)
Pontus Fuchsef187062011-12-14 14:32:23 +01001611 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001612 }
1613out_sleep:
1614 wl1271_ps_elp_sleep(wl);
Pontus Fuchsef187062011-12-14 14:32:23 +01001615out_cleanup:
1616 wlvif->ps_compl = NULL;
Eliad Peller94390642011-05-13 11:57:13 +03001617out_unlock:
1618 mutex_unlock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001619 return ret;
1620
1621}
1622
Eliad Peller0603d892011-10-05 11:55:51 +02001623static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1624 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001625{
Eliad Pellere85d1622011-06-27 13:06:43 +03001626 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001627
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001628 mutex_lock(&wl->mutex);
1629
Eliad Peller53d40d02011-10-10 10:13:02 +02001630 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001631 goto out_unlock;
1632
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001633 ret = wl1271_ps_elp_wakeup(wl);
1634 if (ret < 0)
1635 goto out_unlock;
1636
Eliad Peller0603d892011-10-05 11:55:51 +02001637 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001638
1639 wl1271_ps_elp_sleep(wl);
1640out_unlock:
1641 mutex_unlock(&wl->mutex);
1642 return ret;
1643
1644}
1645
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001646static int wl1271_configure_suspend(struct wl1271 *wl,
1647 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001648{
Eliad Peller536129c2011-10-05 11:55:45 +02001649 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001650 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001651 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001652 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001653 return 0;
1654}
1655
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001656static void wl1271_configure_resume(struct wl1271 *wl,
1657 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001658{
1659 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001660 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1661 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001662
1663 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001664 return;
1665
1666 mutex_lock(&wl->mutex);
1667 ret = wl1271_ps_elp_wakeup(wl);
1668 if (ret < 0)
1669 goto out;
1670
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001671 if (is_sta) {
1672 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001673 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001674 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001675 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001676 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001677 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001678 }
Eliad Peller94390642011-05-13 11:57:13 +03001679
1680 wl1271_ps_elp_sleep(wl);
1681out:
1682 mutex_unlock(&wl->mutex);
1683}
1684
Eliad Peller402e48612011-05-13 11:57:09 +03001685static int wl1271_op_suspend(struct ieee80211_hw *hw,
1686 struct cfg80211_wowlan *wow)
1687{
1688 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001689 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001690 int ret;
1691
Eliad Peller402e48612011-05-13 11:57:09 +03001692 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001693 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001694
Eliad Peller4a859df2011-06-06 12:21:52 +03001695 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001696 wl12xx_for_each_wlvif(wl, wlvif) {
1697 ret = wl1271_configure_suspend(wl, wlvif);
1698 if (ret < 0) {
1699 wl1271_warning("couldn't prepare device to suspend");
1700 return ret;
1701 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001702 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001703 /* flush any remaining work */
1704 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001705
1706 /*
1707 * disable and re-enable interrupts in order to flush
1708 * the threaded_irq
1709 */
1710 wl1271_disable_interrupts(wl);
1711
1712 /*
1713 * set suspended flag to avoid triggering a new threaded_irq
1714 * work. no need for spinlock as interrupts are disabled.
1715 */
1716 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1717
1718 wl1271_enable_interrupts(wl);
1719 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001720 wl12xx_for_each_wlvif(wl, wlvif) {
1721 flush_delayed_work(&wlvif->pspoll_work);
1722 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001723 flush_delayed_work(&wl->elp_work);
1724
Eliad Peller402e48612011-05-13 11:57:09 +03001725 return 0;
1726}
1727
1728static int wl1271_op_resume(struct ieee80211_hw *hw)
1729{
1730 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001731 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001732 unsigned long flags;
1733 bool run_irq_work = false;
1734
Eliad Peller402e48612011-05-13 11:57:09 +03001735 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1736 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001737 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001738
1739 /*
1740 * re-enable irq_work enqueuing, and call irq_work directly if
1741 * there is a pending work.
1742 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001743 spin_lock_irqsave(&wl->wl_lock, flags);
1744 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1745 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1746 run_irq_work = true;
1747 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001748
Eliad Peller4a859df2011-06-06 12:21:52 +03001749 if (run_irq_work) {
1750 wl1271_debug(DEBUG_MAC80211,
1751 "run postponed irq_work directly");
1752 wl1271_irq(0, wl);
1753 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001754 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001755 wl12xx_for_each_wlvif(wl, wlvif) {
1756 wl1271_configure_resume(wl, wlvif);
1757 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001758 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001759
Eliad Peller402e48612011-05-13 11:57:09 +03001760 return 0;
1761}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001762#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001763
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001764static int wl1271_op_start(struct ieee80211_hw *hw)
1765{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001766 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1767
1768 /*
1769 * We have to delay the booting of the hardware because
1770 * we need to know the local MAC address before downloading and
1771 * initializing the firmware. The MAC address cannot be changed
1772 * after boot, and without the proper MAC address, the firmware
1773 * will not function properly.
1774 *
1775 * The MAC address is first known when the corresponding interface
1776 * is added. That is where we will initialize the hardware.
1777 */
1778
1779 return 0;
1780}
1781
1782static void wl1271_op_stop(struct ieee80211_hw *hw)
1783{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001784 struct wl1271 *wl = hw->priv;
1785 int i;
1786
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001787 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001788
Ido Yariv46b0cc92012-01-11 09:42:41 +02001789 /*
1790 * Interrupts must be disabled before setting the state to OFF.
1791 * Otherwise, the interrupt handler might be called and exit without
1792 * reading the interrupt status.
1793 */
1794 wl1271_disable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001795 mutex_lock(&wl->mutex);
1796 if (wl->state == WL1271_STATE_OFF) {
1797 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001798
1799 /*
1800 * This will not necessarily enable interrupts as interrupts
1801 * may have been disabled when op_stop was called. It will,
1802 * however, balance the above call to disable_interrupts().
1803 */
1804 wl1271_enable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001805 return;
1806 }
Ido Yariv46b0cc92012-01-11 09:42:41 +02001807
Eliad Pellerbaf62772011-10-10 10:12:52 +02001808 /*
1809 * this must be before the cancel_work calls below, so that the work
1810 * functions don't perform further work.
1811 */
1812 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001813 mutex_unlock(&wl->mutex);
1814
1815 mutex_lock(&wl_list_mutex);
1816 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001817 mutex_unlock(&wl_list_mutex);
1818
Eliad Pellerbaf62772011-10-10 10:12:52 +02001819 wl1271_flush_deferred_work(wl);
1820 cancel_delayed_work_sync(&wl->scan_complete_work);
1821 cancel_work_sync(&wl->netstack_work);
1822 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001823 cancel_delayed_work_sync(&wl->elp_work);
1824
1825 /* let's notify MAC80211 about the remaining pending TX frames */
1826 wl12xx_tx_reset(wl, true);
1827 mutex_lock(&wl->mutex);
1828
1829 wl1271_power_off(wl);
1830
1831 wl->band = IEEE80211_BAND_2GHZ;
1832
1833 wl->rx_counter = 0;
1834 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1835 wl->tx_blocks_available = 0;
1836 wl->tx_allocated_blocks = 0;
1837 wl->tx_results_count = 0;
1838 wl->tx_packets_count = 0;
1839 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001840 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1841 wl->ap_fw_ps_map = 0;
1842 wl->ap_ps_map = 0;
1843 wl->sched_scanning = false;
1844 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1845 memset(wl->links_map, 0, sizeof(wl->links_map));
1846 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1847 wl->active_sta_count = 0;
1848
1849 /* The system link is always allocated */
1850 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1851
1852 /*
1853 * this is performed after the cancel_work calls and the associated
1854 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1855 * get executed before all these vars have been reset.
1856 */
1857 wl->flags = 0;
1858
1859 wl->tx_blocks_freed = 0;
1860
1861 for (i = 0; i < NUM_TX_QUEUES; i++) {
1862 wl->tx_pkts_freed[i] = 0;
1863 wl->tx_allocated_pkts[i] = 0;
1864 }
1865
1866 wl1271_debugfs_reset(wl);
1867
1868 kfree(wl->fw_status);
1869 wl->fw_status = NULL;
1870 kfree(wl->tx_res_if);
1871 wl->tx_res_if = NULL;
1872 kfree(wl->target_mem_map);
1873 wl->target_mem_map = NULL;
1874
1875 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001876}
1877
Eliad Pellere5a359f2011-10-10 10:13:15 +02001878static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1879{
1880 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1881 WL12XX_MAX_RATE_POLICIES);
1882 if (policy >= WL12XX_MAX_RATE_POLICIES)
1883 return -EBUSY;
1884
1885 __set_bit(policy, wl->rate_policies_map);
1886 *idx = policy;
1887 return 0;
1888}
1889
1890static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1891{
1892 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1893 return;
1894
1895 __clear_bit(*idx, wl->rate_policies_map);
1896 *idx = WL12XX_MAX_RATE_POLICIES;
1897}
1898
Eliad Peller536129c2011-10-05 11:55:45 +02001899static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001900{
Eliad Peller536129c2011-10-05 11:55:45 +02001901 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001902 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001903 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001904 return WL1271_ROLE_P2P_GO;
1905 else
1906 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001907
1908 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001909 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001910 return WL1271_ROLE_P2P_CL;
1911 else
1912 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001913
Eliad Peller227e81e2011-08-14 13:17:26 +03001914 case BSS_TYPE_IBSS:
1915 return WL1271_ROLE_IBSS;
1916
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001917 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001918 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001919 }
1920 return WL12XX_INVALID_ROLE_TYPE;
1921}
1922
Eliad Peller83587502011-10-10 10:12:53 +02001923static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001924{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001925 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001926 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001927
Eliad Peller48e93e42011-10-10 10:12:58 +02001928 /* clear everything but the persistent data */
1929 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001930
1931 switch (ieee80211_vif_type_p2p(vif)) {
1932 case NL80211_IFTYPE_P2P_CLIENT:
1933 wlvif->p2p = 1;
1934 /* fall-through */
1935 case NL80211_IFTYPE_STATION:
1936 wlvif->bss_type = BSS_TYPE_STA_BSS;
1937 break;
1938 case NL80211_IFTYPE_ADHOC:
1939 wlvif->bss_type = BSS_TYPE_IBSS;
1940 break;
1941 case NL80211_IFTYPE_P2P_GO:
1942 wlvif->p2p = 1;
1943 /* fall-through */
1944 case NL80211_IFTYPE_AP:
1945 wlvif->bss_type = BSS_TYPE_AP_BSS;
1946 break;
1947 default:
1948 wlvif->bss_type = MAX_BSS_TYPE;
1949 return -EOPNOTSUPP;
1950 }
1951
Eliad Peller0603d892011-10-05 11:55:51 +02001952 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001953 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001954 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001955
Eliad Pellere936bbe2011-10-05 11:55:56 +02001956 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1957 wlvif->bss_type == BSS_TYPE_IBSS) {
1958 /* init sta/ibss data */
1959 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001960 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1961 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1962 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001963 } else {
1964 /* init ap data */
1965 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1966 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001967 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1968 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1969 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1970 wl12xx_allocate_rate_policy(wl,
1971 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001972 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001973
Eliad Peller83587502011-10-10 10:12:53 +02001974 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1975 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001976 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001977 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001978 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001979 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1980
Eliad Peller1b92f152011-10-10 10:13:09 +02001981 /*
1982 * mac80211 configures some values globally, while we treat them
1983 * per-interface. thus, on init, we have to copy them from wl
1984 */
1985 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001986 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001987 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02001988
Eliad Peller9eb599e2011-10-10 10:12:59 +02001989 INIT_WORK(&wlvif->rx_streaming_enable_work,
1990 wl1271_rx_streaming_enable_work);
1991 INIT_WORK(&wlvif->rx_streaming_disable_work,
1992 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02001993 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02001994 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001995
Eliad Peller9eb599e2011-10-10 10:12:59 +02001996 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1997 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001998 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001999}
2000
Eliad Peller1d095472011-10-10 10:12:49 +02002001static bool wl12xx_init_fw(struct wl1271 *wl)
2002{
2003 int retries = WL1271_BOOT_RETRIES;
2004 bool booted = false;
2005 struct wiphy *wiphy = wl->hw->wiphy;
2006 int ret;
2007
2008 while (retries) {
2009 retries--;
2010 ret = wl1271_chip_wakeup(wl);
2011 if (ret < 0)
2012 goto power_off;
2013
2014 ret = wl1271_boot(wl);
2015 if (ret < 0)
2016 goto power_off;
2017
2018 ret = wl1271_hw_init(wl);
2019 if (ret < 0)
2020 goto irq_disable;
2021
2022 booted = true;
2023 break;
2024
2025irq_disable:
2026 mutex_unlock(&wl->mutex);
2027 /* Unlocking the mutex in the middle of handling is
2028 inherently unsafe. In this case we deem it safe to do,
2029 because we need to let any possibly pending IRQ out of
2030 the system (and while we are WL1271_STATE_OFF the IRQ
2031 work function will not do anything.) Also, any other
2032 possible concurrent operations will fail due to the
2033 current state, hence the wl1271 struct should be safe. */
2034 wl1271_disable_interrupts(wl);
2035 wl1271_flush_deferred_work(wl);
2036 cancel_work_sync(&wl->netstack_work);
2037 mutex_lock(&wl->mutex);
2038power_off:
2039 wl1271_power_off(wl);
2040 }
2041
2042 if (!booted) {
2043 wl1271_error("firmware boot failed despite %d retries",
2044 WL1271_BOOT_RETRIES);
2045 goto out;
2046 }
2047
2048 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2049
2050 /* update hw/fw version info in wiphy struct */
2051 wiphy->hw_version = wl->chip.id;
2052 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2053 sizeof(wiphy->fw_version));
2054
2055 /*
2056 * Now we know if 11a is supported (info from the NVS), so disable
2057 * 11a channels if not supported
2058 */
2059 if (!wl->enable_11a)
2060 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2061
2062 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2063 wl->enable_11a ? "" : "not ");
2064
2065 wl->state = WL1271_STATE_ON;
2066out:
2067 return booted;
2068}
2069
Eliad Peller92e712d2011-12-18 20:25:43 +02002070static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2071{
2072 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2073}
2074
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002075static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2076 struct ieee80211_vif *vif)
2077{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002078 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002079 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002080 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002081 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002082 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002083
Johannes Bergea086352012-01-19 09:29:58 +01002084 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2085 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002086
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002087 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002088 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002089
2090 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002091 ret = wl1271_ps_elp_wakeup(wl);
2092 if (ret < 0)
2093 goto out_unlock;
2094
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002095 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002096 wl1271_debug(DEBUG_MAC80211,
2097 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002098 ret = -EBUSY;
2099 goto out;
2100 }
2101
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002102 /*
2103 * in some very corner case HW recovery scenarios its possible to
2104 * get here before __wl1271_op_remove_interface is complete, so
2105 * opt out if that is the case.
2106 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002107 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2108 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002109 ret = -EBUSY;
2110 goto out;
2111 }
2112
Eliad Peller83587502011-10-10 10:12:53 +02002113 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002114 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002115 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002116
Eliad Peller252efa42011-10-05 11:56:00 +02002117 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002118 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002119 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2120 ret = -EINVAL;
2121 goto out;
2122 }
Eliad Peller1d095472011-10-10 10:12:49 +02002123
Eliad Peller784f6942011-10-05 11:55:39 +02002124 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002125 * TODO: after the nvs issue will be solved, move this block
2126 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002127 */
Eliad Peller1d095472011-10-10 10:12:49 +02002128 if (wl->state == WL1271_STATE_OFF) {
2129 /*
2130 * we still need this in order to configure the fw
2131 * while uploading the nvs
2132 */
2133 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002134
Eliad Peller1d095472011-10-10 10:12:49 +02002135 booted = wl12xx_init_fw(wl);
2136 if (!booted) {
2137 ret = -EINVAL;
2138 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002139 }
Eliad Peller1d095472011-10-10 10:12:49 +02002140 }
Eliad Peller04e80792011-08-14 13:17:09 +03002141
Eliad Peller1d095472011-10-10 10:12:49 +02002142 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2143 wlvif->bss_type == BSS_TYPE_IBSS) {
2144 /*
2145 * The device role is a special role used for
2146 * rx and tx frames prior to association (as
2147 * the STA role can get packets only from
2148 * its associated bssid)
2149 */
Eliad Peller784f6942011-10-05 11:55:39 +02002150 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002151 WL1271_ROLE_DEVICE,
2152 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002153 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002154 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002155 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002156
Eliad Peller1d095472011-10-10 10:12:49 +02002157 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2158 role_type, &wlvif->role_id);
2159 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002160 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002161
2162 ret = wl1271_init_vif_specific(wl, vif);
2163 if (ret < 0)
2164 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002165
2166 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002167 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002168 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002169
2170 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2171 wl->ap_count++;
2172 else
2173 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002174out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002175 wl1271_ps_elp_sleep(wl);
2176out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002177 mutex_unlock(&wl->mutex);
2178
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002179 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002180 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002181 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002182 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002183
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002184 return ret;
2185}
2186
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002187static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002188 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002189 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002190{
Eliad Peller536129c2011-10-05 11:55:45 +02002191 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002192 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002193
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002194 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002195
Eliad Peller10c8cd02011-10-10 10:13:06 +02002196 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2197 return;
2198
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002199 wl->vif = NULL;
2200
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002201 /* because of hardware recovery, we may get here twice */
2202 if (wl->state != WL1271_STATE_ON)
2203 return;
2204
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002205 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002206
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002207 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002208 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002209 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002210
Eliad Pellerbaf62772011-10-10 10:12:52 +02002211 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2212 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002213 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002214 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002215 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002216 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002217 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002218 }
2219
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002220 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2221 /* disable active roles */
2222 ret = wl1271_ps_elp_wakeup(wl);
2223 if (ret < 0)
2224 goto deinit;
2225
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002226 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2227 wlvif->bss_type == BSS_TYPE_IBSS) {
2228 if (wl12xx_dev_role_started(wlvif))
2229 wl12xx_stop_dev(wl, wlvif);
2230
Eliad Peller7edebf52011-10-05 11:55:52 +02002231 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002232 if (ret < 0)
2233 goto deinit;
2234 }
2235
Eliad Peller0603d892011-10-05 11:55:51 +02002236 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002237 if (ret < 0)
2238 goto deinit;
2239
2240 wl1271_ps_elp_sleep(wl);
2241 }
2242deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002243 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002244 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002245
2246 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2247 wlvif->bss_type == BSS_TYPE_IBSS) {
2248 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2249 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2250 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2251 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2252 } else {
2253 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2254 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2255 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2256 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2257 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2258 wl12xx_free_rate_policy(wl,
2259 &wlvif->ap.ucast_rate_idx[i]);
2260 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002261
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002262 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002263 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002264 if (wl->last_wlvif == wlvif)
2265 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002266 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002267 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002268 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002269 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002270
Eliad Pellera4e41302011-10-11 11:49:15 +02002271 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2272 wl->ap_count--;
2273 else
2274 wl->sta_count--;
2275
Eliad Pellerbaf62772011-10-10 10:12:52 +02002276 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002277 del_timer_sync(&wlvif->rx_streaming_timer);
2278 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2279 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002280 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002281
Eliad Pellerbaf62772011-10-10 10:12:52 +02002282 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002283}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002284
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002285static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2286 struct ieee80211_vif *vif)
2287{
2288 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002289 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002290 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002291
2292 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002293
2294 if (wl->state == WL1271_STATE_OFF ||
2295 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2296 goto out;
2297
Juuso Oikarinen67353292010-11-18 15:19:02 +02002298 /*
2299 * wl->vif can be null here if someone shuts down the interface
2300 * just when hardware recovery has been started.
2301 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002302 wl12xx_for_each_wlvif(wl, iter) {
2303 if (iter != wlvif)
2304 continue;
2305
Eliad Peller536129c2011-10-05 11:55:45 +02002306 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002307 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002308 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002309 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002310out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002311 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002312 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002313}
2314
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002315static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2316 struct ieee80211_vif *vif,
2317 enum nl80211_iftype new_type, bool p2p)
2318{
2319 wl1271_op_remove_interface(hw, vif);
2320
2321 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2322 vif->p2p = p2p;
2323 return wl1271_op_add_interface(hw, vif);
2324}
2325
Eliad Peller87fbcb02011-10-05 11:55:41 +02002326static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2327 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002328{
2329 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002330 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002331
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002332 /*
2333 * One of the side effects of the JOIN command is that is clears
2334 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2335 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002336 * Currently the only valid scenario for JOIN during association
2337 * is on roaming, in which case we will also be given new keys.
2338 * Keep the below message for now, unless it starts bothering
2339 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002340 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002341 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002342 wl1271_info("JOIN while associated.");
2343
2344 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002345 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002346
Eliad Peller227e81e2011-08-14 13:17:26 +03002347 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002348 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002349 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002350 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002351 if (ret < 0)
2352 goto out;
2353
Eliad Pellerba8447f2011-10-10 10:13:00 +02002354 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002355 goto out;
2356
2357 /*
2358 * The join command disable the keep-alive mode, shut down its process,
2359 * and also clear the template config, so we need to reset it all after
2360 * the join. The acx_aid starts the keep-alive process, and the order
2361 * of the commands below is relevant.
2362 */
Eliad Peller0603d892011-10-05 11:55:51 +02002363 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002364 if (ret < 0)
2365 goto out;
2366
Eliad Peller0603d892011-10-05 11:55:51 +02002367 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002368 if (ret < 0)
2369 goto out;
2370
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002371 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002372 if (ret < 0)
2373 goto out;
2374
Eliad Peller0603d892011-10-05 11:55:51 +02002375 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2376 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002377 ACX_KEEP_ALIVE_TPL_VALID);
2378 if (ret < 0)
2379 goto out;
2380
2381out:
2382 return ret;
2383}
2384
Eliad Peller0603d892011-10-05 11:55:51 +02002385static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002386{
2387 int ret;
2388
Eliad Peller52630c52011-10-10 10:13:08 +02002389 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002390 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2391
Shahar Levi6d158ff2011-09-08 13:01:33 +03002392 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002393 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002394 }
2395
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002396 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002397 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002398 if (ret < 0)
2399 goto out;
2400
Oz Krakowskib992c682011-06-26 10:36:02 +03002401 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002402 wlvif->tx_security_last_seq_lsb = 0;
2403 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002404
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002405out:
2406 return ret;
2407}
2408
Eliad Peller87fbcb02011-10-05 11:55:41 +02002409static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002410{
Eliad Peller1b92f152011-10-10 10:13:09 +02002411 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002412 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002413}
2414
Eliad Peller87fbcb02011-10-05 11:55:41 +02002415static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2416 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002417{
2418 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002419 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2420
2421 if (idle == cur_idle)
2422 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002423
2424 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002425 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002426 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002427 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002428 if (ret < 0)
2429 goto out;
2430 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002431 wlvif->rate_set =
2432 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2433 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002434 if (ret < 0)
2435 goto out;
2436 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002437 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002438 ACX_KEEP_ALIVE_TPL_INVALID);
2439 if (ret < 0)
2440 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002441 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002442 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002443 /* The current firmware only supports sched_scan in idle */
2444 if (wl->sched_scanning) {
2445 wl1271_scan_sched_scan_stop(wl);
2446 ieee80211_sched_scan_stopped(wl->hw);
2447 }
2448
Eliad Peller679a6732011-10-11 11:55:44 +02002449 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002450 if (ret < 0)
2451 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002452 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002453 }
2454
2455out:
2456 return ret;
2457}
2458
Eliad Peller9f259c42011-10-10 10:13:12 +02002459static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2460 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002461{
Eliad Peller9f259c42011-10-10 10:13:12 +02002462 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2463 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002464
2465 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2466
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002467 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002468 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002469 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002470 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002471 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002472 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002473 wlvif->band = conf->channel->band;
2474 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002475
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002476 if (!is_ap) {
2477 /*
2478 * FIXME: the mac80211 should really provide a fixed
2479 * rate to use here. for now, just use the smallest
2480 * possible rate for the band as a fixed rate for
2481 * association frames and other control messages.
2482 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002483 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002484 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002485
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002486 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002487 wl1271_tx_min_rate_get(wl,
2488 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002489 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002490 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002491 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002492 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002493
Eliad Pellerba8447f2011-10-10 10:13:00 +02002494 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2495 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002496 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002497 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002498 ret = wl12xx_croc(wl,
2499 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002500 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002501 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002502 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002503 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002504 if (ret < 0)
2505 wl1271_warning("cmd join on channel "
2506 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002507 } else {
2508 /*
2509 * change the ROC channel. do it only if we are
2510 * not idle. otherwise, CROC will be called
2511 * anyway.
2512 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002513 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002514 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002515 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002516 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002517 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002518
Eliad Peller679a6732011-10-11 11:55:44 +02002519 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002520 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002521 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002522 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002523 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002524 }
2525 }
2526
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002527 /*
2528 * if mac80211 changes the PSM mode, make sure the mode is not
2529 * incorrectly changed after the pspoll failure active window.
2530 */
2531 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002532 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002533
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002534 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002535 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2536 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002537
2538 /*
2539 * We enter PSM only if we're already associated.
2540 * If we're not, we'll enter it when joining an SSID,
2541 * through the bss_info_changed() hook.
2542 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002543 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002544 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002545 ret = wl1271_ps_set_mode(wl, wlvif,
2546 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002547 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002548 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002549 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002550 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002551 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002552
Eliad Pellerc29bb002011-10-10 10:13:03 +02002553 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002554
Eliad Pellerc29bb002011-10-10 10:13:03 +02002555 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002556 ret = wl1271_ps_set_mode(wl, wlvif,
2557 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002558 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002559 }
2560
Eliad Peller6bd65022011-10-10 10:13:11 +02002561 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002562 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002563 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002564 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002565
Eliad Peller6bd65022011-10-10 10:13:11 +02002566 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002567 }
2568
Eliad Peller9f259c42011-10-10 10:13:12 +02002569 return 0;
2570}
2571
2572static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2573{
2574 struct wl1271 *wl = hw->priv;
2575 struct wl12xx_vif *wlvif;
2576 struct ieee80211_conf *conf = &hw->conf;
2577 int channel, ret = 0;
2578
2579 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2580
2581 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2582 " changed 0x%x",
2583 channel,
2584 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2585 conf->power_level,
2586 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2587 changed);
2588
2589 /*
2590 * mac80211 will go to idle nearly immediately after transmitting some
2591 * frames, such as the deauth. To make sure those frames reach the air,
2592 * wait here until the TX queue is fully flushed.
2593 */
2594 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2595 (conf->flags & IEEE80211_CONF_IDLE))
2596 wl1271_tx_flush(wl);
2597
2598 mutex_lock(&wl->mutex);
2599
2600 /* we support configuring the channel and band even while off */
2601 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2602 wl->band = conf->channel->band;
2603 wl->channel = channel;
2604 }
2605
2606 if (changed & IEEE80211_CONF_CHANGE_POWER)
2607 wl->power_level = conf->power_level;
2608
2609 if (unlikely(wl->state == WL1271_STATE_OFF))
2610 goto out;
2611
2612 ret = wl1271_ps_elp_wakeup(wl);
2613 if (ret < 0)
2614 goto out;
2615
2616 /* configure each interface */
2617 wl12xx_for_each_wlvif(wl, wlvif) {
2618 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2619 if (ret < 0)
2620 goto out_sleep;
2621 }
2622
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002623out_sleep:
2624 wl1271_ps_elp_sleep(wl);
2625
2626out:
2627 mutex_unlock(&wl->mutex);
2628
2629 return ret;
2630}
2631
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002632struct wl1271_filter_params {
2633 bool enabled;
2634 int mc_list_length;
2635 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2636};
2637
Jiri Pirko22bedad2010-04-01 21:22:57 +00002638static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2639 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002640{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002641 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002642 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002643 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002644
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002645 if (unlikely(wl->state == WL1271_STATE_OFF))
2646 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002647
Juuso Oikarinen74441132009-10-13 12:47:53 +03002648 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002649 if (!fp) {
2650 wl1271_error("Out of memory setting filters.");
2651 return 0;
2652 }
2653
2654 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002655 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002656 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2657 fp->enabled = false;
2658 } else {
2659 fp->enabled = true;
2660 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002661 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002662 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002663 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002664 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002665 }
2666
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002667 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002668}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002669
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002670#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2671 FIF_ALLMULTI | \
2672 FIF_FCSFAIL | \
2673 FIF_BCN_PRBRESP_PROMISC | \
2674 FIF_CONTROL | \
2675 FIF_OTHER_BSS)
2676
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002677static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2678 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002679 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002680{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002681 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002682 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002683 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002684
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002685 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002686
Arik Nemtsov7d057862010-10-16 19:25:35 +02002687 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2688 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002689
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002690 mutex_lock(&wl->mutex);
2691
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002692 *total &= WL1271_SUPPORTED_FILTERS;
2693 changed &= WL1271_SUPPORTED_FILTERS;
2694
2695 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002696 goto out;
2697
Ido Yariva6208652011-03-01 15:14:41 +02002698 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002699 if (ret < 0)
2700 goto out;
2701
Eliad Peller6e8cd332011-10-10 10:13:13 +02002702 wl12xx_for_each_wlvif(wl, wlvif) {
2703 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2704 if (*total & FIF_ALLMULTI)
2705 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2706 false,
2707 NULL, 0);
2708 else if (fp)
2709 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2710 fp->enabled,
2711 fp->mc_list,
2712 fp->mc_list_length);
2713 if (ret < 0)
2714 goto out_sleep;
2715 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002716 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002717
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002718 /*
2719 * the fw doesn't provide an api to configure the filters. instead,
2720 * the filters configuration is based on the active roles / ROC
2721 * state.
2722 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002723
2724out_sleep:
2725 wl1271_ps_elp_sleep(wl);
2726
2727out:
2728 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002729 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002730}
2731
Eliad Peller170d0e62011-10-05 11:56:06 +02002732static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2733 u8 id, u8 key_type, u8 key_size,
2734 const u8 *key, u8 hlid, u32 tx_seq_32,
2735 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002736{
2737 struct wl1271_ap_key *ap_key;
2738 int i;
2739
2740 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2741
2742 if (key_size > MAX_KEY_SIZE)
2743 return -EINVAL;
2744
2745 /*
2746 * Find next free entry in ap_keys. Also check we are not replacing
2747 * an existing key.
2748 */
2749 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002750 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002751 break;
2752
Eliad Peller170d0e62011-10-05 11:56:06 +02002753 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002754 wl1271_warning("trying to record key replacement");
2755 return -EINVAL;
2756 }
2757 }
2758
2759 if (i == MAX_NUM_KEYS)
2760 return -EBUSY;
2761
2762 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2763 if (!ap_key)
2764 return -ENOMEM;
2765
2766 ap_key->id = id;
2767 ap_key->key_type = key_type;
2768 ap_key->key_size = key_size;
2769 memcpy(ap_key->key, key, key_size);
2770 ap_key->hlid = hlid;
2771 ap_key->tx_seq_32 = tx_seq_32;
2772 ap_key->tx_seq_16 = tx_seq_16;
2773
Eliad Peller170d0e62011-10-05 11:56:06 +02002774 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002775 return 0;
2776}
2777
Eliad Peller170d0e62011-10-05 11:56:06 +02002778static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002779{
2780 int i;
2781
2782 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002783 kfree(wlvif->ap.recorded_keys[i]);
2784 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002785 }
2786}
2787
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002788static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002789{
2790 int i, ret = 0;
2791 struct wl1271_ap_key *key;
2792 bool wep_key_added = false;
2793
2794 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002795 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002796 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002797 break;
2798
Eliad Peller170d0e62011-10-05 11:56:06 +02002799 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002800 hlid = key->hlid;
2801 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002802 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002803
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002804 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002805 key->id, key->key_type,
2806 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002807 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002808 key->tx_seq_16);
2809 if (ret < 0)
2810 goto out;
2811
2812 if (key->key_type == KEY_WEP)
2813 wep_key_added = true;
2814 }
2815
2816 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002817 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002818 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002819 if (ret < 0)
2820 goto out;
2821 }
2822
2823out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002824 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002825 return ret;
2826}
2827
Eliad Peller536129c2011-10-05 11:55:45 +02002828static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2829 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002830 u8 key_size, const u8 *key, u32 tx_seq_32,
2831 u16 tx_seq_16, struct ieee80211_sta *sta)
2832{
2833 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002834 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002835
2836 if (is_ap) {
2837 struct wl1271_station *wl_sta;
2838 u8 hlid;
2839
2840 if (sta) {
2841 wl_sta = (struct wl1271_station *)sta->drv_priv;
2842 hlid = wl_sta->hlid;
2843 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002844 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002845 }
2846
Eliad Peller53d40d02011-10-10 10:13:02 +02002847 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002848 /*
2849 * We do not support removing keys after AP shutdown.
2850 * Pretend we do to make mac80211 happy.
2851 */
2852 if (action != KEY_ADD_OR_REPLACE)
2853 return 0;
2854
Eliad Peller170d0e62011-10-05 11:56:06 +02002855 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002856 key_type, key_size,
2857 key, hlid, tx_seq_32,
2858 tx_seq_16);
2859 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002860 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002861 id, key_type, key_size,
2862 key, hlid, tx_seq_32,
2863 tx_seq_16);
2864 }
2865
2866 if (ret < 0)
2867 return ret;
2868 } else {
2869 const u8 *addr;
2870 static const u8 bcast_addr[ETH_ALEN] = {
2871 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2872 };
2873
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002874 /*
2875 * A STA set to GEM cipher requires 2 tx spare blocks.
2876 * Return to default value when GEM cipher key is removed
2877 */
2878 if (key_type == KEY_GEM) {
2879 if (action == KEY_ADD_OR_REPLACE)
2880 wl->tx_spare_blocks = 2;
2881 else if (action == KEY_REMOVE)
2882 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2883 }
2884
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002885 addr = sta ? sta->addr : bcast_addr;
2886
2887 if (is_zero_ether_addr(addr)) {
2888 /* We dont support TX only encryption */
2889 return -EOPNOTSUPP;
2890 }
2891
2892 /* The wl1271 does not allow to remove unicast keys - they
2893 will be cleared automatically on next CMD_JOIN. Ignore the
2894 request silently, as we dont want the mac80211 to emit
2895 an error message. */
2896 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2897 return 0;
2898
Eliad Peller010d3d32011-08-14 13:17:31 +03002899 /* don't remove key if hlid was already deleted */
2900 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002901 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002902 return 0;
2903
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002904 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002905 id, key_type, key_size,
2906 key, addr, tx_seq_32,
2907 tx_seq_16);
2908 if (ret < 0)
2909 return ret;
2910
2911 /* the default WEP key needs to be configured at least once */
2912 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002913 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002914 wlvif->default_key,
2915 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002916 if (ret < 0)
2917 return ret;
2918 }
2919 }
2920
2921 return 0;
2922}
2923
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002924static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2925 struct ieee80211_vif *vif,
2926 struct ieee80211_sta *sta,
2927 struct ieee80211_key_conf *key_conf)
2928{
2929 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002930 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002931 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002932 u32 tx_seq_32 = 0;
2933 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002934 u8 key_type;
2935
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002936 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2937
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002938 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002939 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002940 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002941 key_conf->keylen, key_conf->flags);
2942 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2943
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002944 mutex_lock(&wl->mutex);
2945
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002946 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2947 ret = -EAGAIN;
2948 goto out_unlock;
2949 }
2950
Ido Yariva6208652011-03-01 15:14:41 +02002951 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002952 if (ret < 0)
2953 goto out_unlock;
2954
Johannes Berg97359d12010-08-10 09:46:38 +02002955 switch (key_conf->cipher) {
2956 case WLAN_CIPHER_SUITE_WEP40:
2957 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002958 key_type = KEY_WEP;
2959
2960 key_conf->hw_key_idx = key_conf->keyidx;
2961 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002962 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002963 key_type = KEY_TKIP;
2964
2965 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002966 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2967 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002968 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002969 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002970 key_type = KEY_AES;
2971
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002972 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002973 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2974 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002975 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002976 case WL1271_CIPHER_SUITE_GEM:
2977 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002978 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2979 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002980 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002981 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002982 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002983
2984 ret = -EOPNOTSUPP;
2985 goto out_sleep;
2986 }
2987
2988 switch (cmd) {
2989 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002990 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002991 key_conf->keyidx, key_type,
2992 key_conf->keylen, key_conf->key,
2993 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002994 if (ret < 0) {
2995 wl1271_error("Could not add or replace key");
2996 goto out_sleep;
2997 }
2998 break;
2999
3000 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003001 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003002 key_conf->keyidx, key_type,
3003 key_conf->keylen, key_conf->key,
3004 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003005 if (ret < 0) {
3006 wl1271_error("Could not remove key");
3007 goto out_sleep;
3008 }
3009 break;
3010
3011 default:
3012 wl1271_error("Unsupported key cmd 0x%x", cmd);
3013 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003014 break;
3015 }
3016
3017out_sleep:
3018 wl1271_ps_elp_sleep(wl);
3019
3020out_unlock:
3021 mutex_unlock(&wl->mutex);
3022
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003023 return ret;
3024}
3025
3026static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003027 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003028 struct cfg80211_scan_request *req)
3029{
3030 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003031 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3032
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003033 int ret;
3034 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003035 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003036
3037 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3038
3039 if (req->n_ssids) {
3040 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003041 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003042 }
3043
3044 mutex_lock(&wl->mutex);
3045
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003046 if (wl->state == WL1271_STATE_OFF) {
3047 /*
3048 * We cannot return -EBUSY here because cfg80211 will expect
3049 * a call to ieee80211_scan_completed if we do - in this case
3050 * there won't be any call.
3051 */
3052 ret = -EAGAIN;
3053 goto out;
3054 }
3055
Ido Yariva6208652011-03-01 15:14:41 +02003056 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003057 if (ret < 0)
3058 goto out;
3059
Eliad Peller92e712d2011-12-18 20:25:43 +02003060 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
3061 test_bit(wlvif->role_id, wl->roc_map)) {
3062 /* don't allow scanning right now */
3063 ret = -EBUSY;
3064 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003065 }
3066
Eliad Peller92e712d2011-12-18 20:25:43 +02003067 /* cancel ROC before scanning */
3068 if (wl12xx_dev_role_started(wlvif))
3069 wl12xx_stop_dev(wl, wlvif);
3070
Eliad Peller784f6942011-10-05 11:55:39 +02003071 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003072out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003073 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003074out:
3075 mutex_unlock(&wl->mutex);
3076
3077 return ret;
3078}
3079
Eliad Peller73ecce32011-06-27 13:06:45 +03003080static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3081 struct ieee80211_vif *vif)
3082{
3083 struct wl1271 *wl = hw->priv;
3084 int ret;
3085
3086 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3087
3088 mutex_lock(&wl->mutex);
3089
3090 if (wl->state == WL1271_STATE_OFF)
3091 goto out;
3092
3093 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3094 goto out;
3095
3096 ret = wl1271_ps_elp_wakeup(wl);
3097 if (ret < 0)
3098 goto out;
3099
3100 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3101 ret = wl1271_scan_stop(wl);
3102 if (ret < 0)
3103 goto out_sleep;
3104 }
3105 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3106 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003107 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003108 wl->scan.req = NULL;
3109 ieee80211_scan_completed(wl->hw, true);
3110
3111out_sleep:
3112 wl1271_ps_elp_sleep(wl);
3113out:
3114 mutex_unlock(&wl->mutex);
3115
3116 cancel_delayed_work_sync(&wl->scan_complete_work);
3117}
3118
Luciano Coelho33c2c062011-05-10 14:46:02 +03003119static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3120 struct ieee80211_vif *vif,
3121 struct cfg80211_sched_scan_request *req,
3122 struct ieee80211_sched_scan_ies *ies)
3123{
3124 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003125 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003126 int ret;
3127
3128 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3129
3130 mutex_lock(&wl->mutex);
3131
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003132 if (wl->state == WL1271_STATE_OFF) {
3133 ret = -EAGAIN;
3134 goto out;
3135 }
3136
Luciano Coelho33c2c062011-05-10 14:46:02 +03003137 ret = wl1271_ps_elp_wakeup(wl);
3138 if (ret < 0)
3139 goto out;
3140
Eliad Peller536129c2011-10-05 11:55:45 +02003141 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003142 if (ret < 0)
3143 goto out_sleep;
3144
Eliad Peller536129c2011-10-05 11:55:45 +02003145 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003146 if (ret < 0)
3147 goto out_sleep;
3148
3149 wl->sched_scanning = true;
3150
3151out_sleep:
3152 wl1271_ps_elp_sleep(wl);
3153out:
3154 mutex_unlock(&wl->mutex);
3155 return ret;
3156}
3157
3158static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3159 struct ieee80211_vif *vif)
3160{
3161 struct wl1271 *wl = hw->priv;
3162 int ret;
3163
3164 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3165
3166 mutex_lock(&wl->mutex);
3167
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003168 if (wl->state == WL1271_STATE_OFF)
3169 goto out;
3170
Luciano Coelho33c2c062011-05-10 14:46:02 +03003171 ret = wl1271_ps_elp_wakeup(wl);
3172 if (ret < 0)
3173 goto out;
3174
3175 wl1271_scan_sched_scan_stop(wl);
3176
3177 wl1271_ps_elp_sleep(wl);
3178out:
3179 mutex_unlock(&wl->mutex);
3180}
3181
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003182static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3183{
3184 struct wl1271 *wl = hw->priv;
3185 int ret = 0;
3186
3187 mutex_lock(&wl->mutex);
3188
3189 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3190 ret = -EAGAIN;
3191 goto out;
3192 }
3193
Ido Yariva6208652011-03-01 15:14:41 +02003194 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003195 if (ret < 0)
3196 goto out;
3197
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003198 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003199 if (ret < 0)
3200 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3201
3202 wl1271_ps_elp_sleep(wl);
3203
3204out:
3205 mutex_unlock(&wl->mutex);
3206
3207 return ret;
3208}
3209
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003210static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3211{
3212 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003213 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003214 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003215
3216 mutex_lock(&wl->mutex);
3217
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003218 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3219 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003220 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003221 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003222
Ido Yariva6208652011-03-01 15:14:41 +02003223 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003224 if (ret < 0)
3225 goto out;
3226
Eliad Peller6e8cd332011-10-10 10:13:13 +02003227 wl12xx_for_each_wlvif(wl, wlvif) {
3228 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3229 if (ret < 0)
3230 wl1271_warning("set rts threshold failed: %d", ret);
3231 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003232 wl1271_ps_elp_sleep(wl);
3233
3234out:
3235 mutex_unlock(&wl->mutex);
3236
3237 return ret;
3238}
3239
Eliad Peller1fe9f162011-10-05 11:55:48 +02003240static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003241 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003242{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003243 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003244 u8 ssid_len;
3245 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3246 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003247
Eliad Peller889cb362011-05-01 09:56:45 +03003248 if (!ptr) {
3249 wl1271_error("No SSID in IEs!");
3250 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003251 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003252
Eliad Peller889cb362011-05-01 09:56:45 +03003253 ssid_len = ptr[1];
3254 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3255 wl1271_error("SSID is too long!");
3256 return -EINVAL;
3257 }
3258
Eliad Peller1fe9f162011-10-05 11:55:48 +02003259 wlvif->ssid_len = ssid_len;
3260 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003261 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003262}
3263
Eliad Pellerd48055d2011-09-15 12:07:04 +03003264static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3265{
3266 int len;
3267 const u8 *next, *end = skb->data + skb->len;
3268 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3269 skb->len - ieoffset);
3270 if (!ie)
3271 return;
3272 len = ie[1] + 2;
3273 next = ie + len;
3274 memmove(ie, next, end - next);
3275 skb_trim(skb, skb->len - len);
3276}
3277
Eliad Peller26b4bf22011-09-15 12:07:05 +03003278static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3279 unsigned int oui, u8 oui_type,
3280 int ieoffset)
3281{
3282 int len;
3283 const u8 *next, *end = skb->data + skb->len;
3284 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3285 skb->data + ieoffset,
3286 skb->len - ieoffset);
3287 if (!ie)
3288 return;
3289 len = ie[1] + 2;
3290 next = ie + len;
3291 memmove(ie, next, end - next);
3292 skb_trim(skb, skb->len - len);
3293}
3294
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003295static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3296 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003297{
3298 struct sk_buff *skb;
3299 int ret;
3300
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003301 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003302 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003303 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003304
3305 ret = wl1271_cmd_template_set(wl,
3306 CMD_TEMPL_AP_PROBE_RESPONSE,
3307 skb->data,
3308 skb->len, 0,
3309 rates);
3310
3311 dev_kfree_skb(skb);
3312 return ret;
3313}
3314
3315static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3316 struct ieee80211_vif *vif,
3317 u8 *probe_rsp_data,
3318 size_t probe_rsp_len,
3319 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003320{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003321 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3322 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003323 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3324 int ssid_ie_offset, ie_offset, templ_len;
3325 const u8 *ptr;
3326
3327 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003328 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003329 return wl1271_cmd_template_set(wl,
3330 CMD_TEMPL_AP_PROBE_RESPONSE,
3331 probe_rsp_data,
3332 probe_rsp_len, 0,
3333 rates);
3334
3335 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3336 wl1271_error("probe_rsp template too big");
3337 return -EINVAL;
3338 }
3339
3340 /* start searching from IE offset */
3341 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3342
3343 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3344 probe_rsp_len - ie_offset);
3345 if (!ptr) {
3346 wl1271_error("No SSID in beacon!");
3347 return -EINVAL;
3348 }
3349
3350 ssid_ie_offset = ptr - probe_rsp_data;
3351 ptr += (ptr[1] + 2);
3352
3353 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3354
3355 /* insert SSID from bss_conf */
3356 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3357 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3358 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3359 bss_conf->ssid, bss_conf->ssid_len);
3360 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3361
3362 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3363 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3364 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3365
3366 return wl1271_cmd_template_set(wl,
3367 CMD_TEMPL_AP_PROBE_RESPONSE,
3368 probe_rsp_templ,
3369 templ_len, 0,
3370 rates);
3371}
3372
Arik Nemtsove78a2872010-10-16 19:07:21 +02003373static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003374 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003375 struct ieee80211_bss_conf *bss_conf,
3376 u32 changed)
3377{
Eliad Peller0603d892011-10-05 11:55:51 +02003378 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003379 int ret = 0;
3380
3381 if (changed & BSS_CHANGED_ERP_SLOT) {
3382 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003383 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003384 else
Eliad Peller0603d892011-10-05 11:55:51 +02003385 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003386 if (ret < 0) {
3387 wl1271_warning("Set slot time failed %d", ret);
3388 goto out;
3389 }
3390 }
3391
3392 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3393 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003394 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003395 else
Eliad Peller0603d892011-10-05 11:55:51 +02003396 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003397 }
3398
3399 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3400 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003401 ret = wl1271_acx_cts_protect(wl, wlvif,
3402 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003403 else
Eliad Peller0603d892011-10-05 11:55:51 +02003404 ret = wl1271_acx_cts_protect(wl, wlvif,
3405 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003406 if (ret < 0) {
3407 wl1271_warning("Set ctsprotect failed %d", ret);
3408 goto out;
3409 }
3410 }
3411
3412out:
3413 return ret;
3414}
3415
3416static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3417 struct ieee80211_vif *vif,
3418 struct ieee80211_bss_conf *bss_conf,
3419 u32 changed)
3420{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003421 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003422 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003423 int ret = 0;
3424
3425 if ((changed & BSS_CHANGED_BEACON_INT)) {
3426 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3427 bss_conf->beacon_int);
3428
Eliad Peller6a899792011-10-05 11:55:58 +02003429 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003430 }
3431
Arik Nemtsov560f0022011-11-08 18:46:54 +02003432 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3433 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003434 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3435 wl1271_debug(DEBUG_AP, "probe response updated");
3436 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3437 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003438 }
3439
Arik Nemtsove78a2872010-10-16 19:07:21 +02003440 if ((changed & BSS_CHANGED_BEACON)) {
3441 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003442 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003443 int ieoffset = offsetof(struct ieee80211_mgmt,
3444 u.beacon.variable);
3445 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3446 u16 tmpl_id;
3447
Arik Nemtsov560f0022011-11-08 18:46:54 +02003448 if (!beacon) {
3449 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003450 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003451 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003452
3453 wl1271_debug(DEBUG_MASTER, "beacon updated");
3454
Eliad Peller1fe9f162011-10-05 11:55:48 +02003455 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003456 if (ret < 0) {
3457 dev_kfree_skb(beacon);
3458 goto out;
3459 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003460 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003461 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3462 CMD_TEMPL_BEACON;
3463 ret = wl1271_cmd_template_set(wl, tmpl_id,
3464 beacon->data,
3465 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003466 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003467 if (ret < 0) {
3468 dev_kfree_skb(beacon);
3469 goto out;
3470 }
3471
Arik Nemtsov560f0022011-11-08 18:46:54 +02003472 /*
3473 * In case we already have a probe-resp beacon set explicitly
3474 * by usermode, don't use the beacon data.
3475 */
3476 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3477 goto end_bcn;
3478
Eliad Pellerd48055d2011-09-15 12:07:04 +03003479 /* remove TIM ie from probe response */
3480 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3481
Eliad Peller26b4bf22011-09-15 12:07:05 +03003482 /*
3483 * remove p2p ie from probe response.
3484 * the fw reponds to probe requests that don't include
3485 * the p2p ie. probe requests with p2p ie will be passed,
3486 * and will be responded by the supplicant (the spec
3487 * forbids including the p2p ie when responding to probe
3488 * requests that didn't include it).
3489 */
3490 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3491 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3492
Arik Nemtsove78a2872010-10-16 19:07:21 +02003493 hdr = (struct ieee80211_hdr *) beacon->data;
3494 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3495 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003496 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003497 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003498 beacon->data,
3499 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003500 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003501 else
3502 ret = wl1271_cmd_template_set(wl,
3503 CMD_TEMPL_PROBE_RESPONSE,
3504 beacon->data,
3505 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003506 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003507end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003508 dev_kfree_skb(beacon);
3509 if (ret < 0)
3510 goto out;
3511 }
3512
3513out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003514 if (ret != 0)
3515 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003516 return ret;
3517}
3518
3519/* AP mode changes */
3520static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003521 struct ieee80211_vif *vif,
3522 struct ieee80211_bss_conf *bss_conf,
3523 u32 changed)
3524{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003525 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003526 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003527
Arik Nemtsove78a2872010-10-16 19:07:21 +02003528 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3529 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003530
Eliad Peller87fbcb02011-10-05 11:55:41 +02003531 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003532 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003533 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003534 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003535
Eliad Peller87fbcb02011-10-05 11:55:41 +02003536 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003537 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003538 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003539 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003540 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003541
Eliad Peller784f6942011-10-05 11:55:39 +02003542 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003543 if (ret < 0)
3544 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003545 }
3546
Arik Nemtsove78a2872010-10-16 19:07:21 +02003547 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3548 if (ret < 0)
3549 goto out;
3550
3551 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3552 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003553 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003554 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003555 if (ret < 0)
3556 goto out;
3557
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003558 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003559 if (ret < 0)
3560 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003561
Eliad Peller53d40d02011-10-10 10:13:02 +02003562 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003563 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003564 }
3565 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003566 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003567 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003568 if (ret < 0)
3569 goto out;
3570
Eliad Peller53d40d02011-10-10 10:13:02 +02003571 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003572 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3573 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003574 wl1271_debug(DEBUG_AP, "stopped AP");
3575 }
3576 }
3577 }
3578
Eliad Peller0603d892011-10-05 11:55:51 +02003579 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003580 if (ret < 0)
3581 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003582
3583 /* Handle HT information change */
3584 if ((changed & BSS_CHANGED_HT) &&
3585 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003586 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003587 bss_conf->ht_operation_mode);
3588 if (ret < 0) {
3589 wl1271_warning("Set ht information failed %d", ret);
3590 goto out;
3591 }
3592 }
3593
Arik Nemtsove78a2872010-10-16 19:07:21 +02003594out:
3595 return;
3596}
3597
3598/* STA/IBSS mode changes */
3599static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3600 struct ieee80211_vif *vif,
3601 struct ieee80211_bss_conf *bss_conf,
3602 u32 changed)
3603{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003604 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003605 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003606 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003607 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003608 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003609 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003610 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003611 bool sta_exists = false;
3612 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003613
3614 if (is_ibss) {
3615 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3616 changed);
3617 if (ret < 0)
3618 goto out;
3619 }
3620
Eliad Peller227e81e2011-08-14 13:17:26 +03003621 if (changed & BSS_CHANGED_IBSS) {
3622 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003623 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003624 ibss_joined = true;
3625 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003626 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3627 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003628 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003629 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003630 }
3631 }
3632 }
3633
3634 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003635 do_join = true;
3636
3637 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003638 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003639 do_join = true;
3640
Eliad Peller227e81e2011-08-14 13:17:26 +03003641 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003642 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3643 bss_conf->enable_beacon ? "enabled" : "disabled");
3644
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003645 do_join = true;
3646 }
3647
Eliad Pellerc31e4942011-10-23 08:21:55 +02003648 if (changed & BSS_CHANGED_IDLE) {
3649 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3650 if (ret < 0)
3651 wl1271_warning("idle mode change failed %d", ret);
3652 }
3653
Arik Nemtsove78a2872010-10-16 19:07:21 +02003654 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003655 bool enable = false;
3656 if (bss_conf->cqm_rssi_thold)
3657 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003658 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003659 bss_conf->cqm_rssi_thold,
3660 bss_conf->cqm_rssi_hyst);
3661 if (ret < 0)
3662 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003663 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003664 }
3665
Eliad Pellercdf09492011-10-05 11:55:44 +02003666 if (changed & BSS_CHANGED_BSSID)
3667 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003668 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003669 if (ret < 0)
3670 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003671
Eliad Peller784f6942011-10-05 11:55:39 +02003672 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003673 if (ret < 0)
3674 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003675
Eliad Pellerfa287b82010-12-26 09:27:50 +01003676 /* Need to update the BSSID (for filtering etc) */
3677 do_join = true;
3678 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003679
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003680 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3681 rcu_read_lock();
3682 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3683 if (!sta)
3684 goto sta_not_found;
3685
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003686 /* save the supp_rates of the ap */
3687 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3688 if (sta->ht_cap.ht_supported)
3689 sta_rate_set |=
3690 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003691 sta_ht_cap = sta->ht_cap;
3692 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003693
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003694sta_not_found:
3695 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003696 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003697
Arik Nemtsove78a2872010-10-16 19:07:21 +02003698 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003699 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003700 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003701 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003702 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003703 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003704
Eliad Peller74ec8392011-10-05 11:56:02 +02003705 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003706
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003707 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003708 * use basic rates from AP, and determine lowest rate
3709 * to use with control frames.
3710 */
3711 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003712 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003713 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003714 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003715 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003716 wl1271_tx_min_rate_get(wl,
3717 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003718 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003719 wlvif->rate_set =
3720 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003721 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003722 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003723 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003724 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003725 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003726
3727 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003728 * with wl1271, we don't need to update the
3729 * beacon_int and dtim_period, because the firmware
3730 * updates it by itself when the first beacon is
3731 * received after a join.
3732 */
Eliad Peller6840e372011-10-05 11:55:50 +02003733 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003734 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003735 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003736
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003737 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003738 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003739 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003740 dev_kfree_skb(wlvif->probereq);
3741 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003742 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003743 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003744 ieoffset = offsetof(struct ieee80211_mgmt,
3745 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003746 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003747
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003748 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003749 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003750 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003751 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003752 } else {
3753 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003754 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003755 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3756 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003757 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003758 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3759 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003760 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003761
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003762 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003763 dev_kfree_skb(wlvif->probereq);
3764 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003765
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003766 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003767 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003768
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003769 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003770 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003771 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003772 wl1271_tx_min_rate_get(wl,
3773 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003774 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003775 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003776 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003777
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003778 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003779 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003780
3781 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003782 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003783 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003784 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003785
3786 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003787 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003788 u32 conf_flags = wl->hw->conf.flags;
3789 /*
3790 * we might have to disable roc, if there was
3791 * no IF_OPER_UP notification.
3792 */
3793 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003794 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003795 if (ret < 0)
3796 goto out;
3797 }
3798 /*
3799 * (we also need to disable roc in case of
3800 * roaming on the same channel. until we will
3801 * have a better flow...)
3802 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003803 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3804 ret = wl12xx_croc(wl,
3805 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003806 if (ret < 0)
3807 goto out;
3808 }
3809
Eliad Peller0603d892011-10-05 11:55:51 +02003810 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003811 if (!(conf_flags & IEEE80211_CONF_IDLE))
3812 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003813 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003814 }
3815 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003816
Eliad Pellerd192d262011-05-24 14:33:08 +03003817 if (changed & BSS_CHANGED_IBSS) {
3818 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3819 bss_conf->ibss_joined);
3820
3821 if (bss_conf->ibss_joined) {
3822 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003823 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003824 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003825 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003826 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003827 wl1271_tx_min_rate_get(wl,
3828 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003829
Shahar Levi06b660e2011-09-05 13:54:36 +03003830 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003831 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3832 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003833 if (ret < 0)
3834 goto out;
3835 }
3836 }
3837
Eliad Peller0603d892011-10-05 11:55:51 +02003838 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003839 if (ret < 0)
3840 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003841
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003842 if (changed & BSS_CHANGED_ARP_FILTER) {
3843 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003844 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003845
Eliad Pellerc5312772010-12-09 11:31:27 +02003846 if (bss_conf->arp_addr_cnt == 1 &&
3847 bss_conf->arp_filter_enabled) {
3848 /*
3849 * The template should have been configured only upon
3850 * association. however, it seems that the correct ip
3851 * isn't being set (when sending), so we have to
3852 * reconfigure the template upon every ip change.
3853 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003854 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003855 if (ret < 0) {
3856 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003857 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003858 }
3859
Eliad Peller0603d892011-10-05 11:55:51 +02003860 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003861 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003862 addr);
3863 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003864 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003865
3866 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003867 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003868 }
3869
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003870 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003871 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003872 if (ret < 0) {
3873 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003874 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003875 }
Eliad Peller251c1772011-08-14 13:17:17 +03003876
3877 /* ROC until connected (after EAPOL exchange) */
3878 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003879 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003880 if (ret < 0)
3881 goto out;
3882
Eliad Pellerba8447f2011-10-10 10:13:00 +02003883 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003884 ieee80211_get_operstate(vif));
3885 }
3886 /*
3887 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003888 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003889 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003890 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003891 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003892 if (ret < 0)
3893 goto out;
3894 }
Eliad Peller05dba352011-08-23 16:37:01 +03003895
3896 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003897 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3898 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003899 enum wl1271_cmd_ps_mode mode;
3900
3901 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003902 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003903 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003904 true);
3905 if (ret < 0)
3906 goto out;
3907 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003908 }
3909
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003910 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003911 if (sta_exists) {
3912 if ((changed & BSS_CHANGED_HT) &&
3913 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003914 ret = wl1271_acx_set_ht_capabilities(wl,
3915 &sta_ht_cap,
3916 true,
Eliad Peller154da672011-10-05 11:55:53 +02003917 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003918 if (ret < 0) {
3919 wl1271_warning("Set ht cap true failed %d",
3920 ret);
3921 goto out;
3922 }
3923 }
3924 /* handle new association without HT and disassociation */
3925 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003926 ret = wl1271_acx_set_ht_capabilities(wl,
3927 &sta_ht_cap,
3928 false,
Eliad Peller154da672011-10-05 11:55:53 +02003929 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003930 if (ret < 0) {
3931 wl1271_warning("Set ht cap false failed %d",
3932 ret);
3933 goto out;
3934 }
3935 }
3936 }
3937
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003938 /* Handle HT information change. Done after join. */
3939 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003940 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003941 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003942 bss_conf->ht_operation_mode);
3943 if (ret < 0) {
3944 wl1271_warning("Set ht information failed %d", ret);
3945 goto out;
3946 }
3947 }
3948
Arik Nemtsove78a2872010-10-16 19:07:21 +02003949out:
3950 return;
3951}
3952
3953static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3954 struct ieee80211_vif *vif,
3955 struct ieee80211_bss_conf *bss_conf,
3956 u32 changed)
3957{
3958 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003959 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3960 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003961 int ret;
3962
3963 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3964 (int)changed);
3965
3966 mutex_lock(&wl->mutex);
3967
3968 if (unlikely(wl->state == WL1271_STATE_OFF))
3969 goto out;
3970
Eliad Peller10c8cd02011-10-10 10:13:06 +02003971 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3972 goto out;
3973
Ido Yariva6208652011-03-01 15:14:41 +02003974 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003975 if (ret < 0)
3976 goto out;
3977
3978 if (is_ap)
3979 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3980 else
3981 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3982
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003983 wl1271_ps_elp_sleep(wl);
3984
3985out:
3986 mutex_unlock(&wl->mutex);
3987}
3988
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003989static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3990 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003991 const struct ieee80211_tx_queue_params *params)
3992{
3993 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003994 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003995 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003996 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003997
3998 mutex_lock(&wl->mutex);
3999
4000 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
4001
Kalle Valo4695dc92010-03-18 12:26:38 +02004002 if (params->uapsd)
4003 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
4004 else
4005 ps_scheme = CONF_PS_SCHEME_LEGACY;
4006
Eliad Peller5b37ddf2011-12-18 20:25:40 +02004007 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004008 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004009
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004010 ret = wl1271_ps_elp_wakeup(wl);
4011 if (ret < 0)
4012 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004013
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004014 /*
4015 * the txop is confed in units of 32us by the mac80211,
4016 * we need us
4017 */
Eliad Peller0603d892011-10-05 11:55:51 +02004018 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004019 params->cw_min, params->cw_max,
4020 params->aifs, params->txop << 5);
4021 if (ret < 0)
4022 goto out_sleep;
4023
Eliad Peller0603d892011-10-05 11:55:51 +02004024 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004025 CONF_CHANNEL_TYPE_EDCF,
4026 wl1271_tx_get_queue(queue),
4027 ps_scheme, CONF_ACK_POLICY_LEGACY,
4028 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004029
4030out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004031 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004032
4033out:
4034 mutex_unlock(&wl->mutex);
4035
4036 return ret;
4037}
4038
Eliad Peller37a41b42011-09-21 14:06:11 +03004039static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4040 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004041{
4042
4043 struct wl1271 *wl = hw->priv;
4044 u64 mactime = ULLONG_MAX;
4045 int ret;
4046
4047 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4048
4049 mutex_lock(&wl->mutex);
4050
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004051 if (unlikely(wl->state == WL1271_STATE_OFF))
4052 goto out;
4053
Ido Yariva6208652011-03-01 15:14:41 +02004054 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004055 if (ret < 0)
4056 goto out;
4057
4058 ret = wl1271_acx_tsf_info(wl, &mactime);
4059 if (ret < 0)
4060 goto out_sleep;
4061
4062out_sleep:
4063 wl1271_ps_elp_sleep(wl);
4064
4065out:
4066 mutex_unlock(&wl->mutex);
4067 return mactime;
4068}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004069
John W. Linvilleece550d2010-07-28 16:41:06 -04004070static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4071 struct survey_info *survey)
4072{
4073 struct wl1271 *wl = hw->priv;
4074 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004075
John W. Linvilleece550d2010-07-28 16:41:06 -04004076 if (idx != 0)
4077 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004078
John W. Linvilleece550d2010-07-28 16:41:06 -04004079 survey->channel = conf->channel;
4080 survey->filled = SURVEY_INFO_NOISE_DBM;
4081 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004082
John W. Linvilleece550d2010-07-28 16:41:06 -04004083 return 0;
4084}
4085
Arik Nemtsov409622e2011-02-23 00:22:29 +02004086static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004087 struct wl12xx_vif *wlvif,
4088 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004089{
4090 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004091 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004092
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004093
4094 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004095 wl1271_warning("could not allocate HLID - too much stations");
4096 return -EBUSY;
4097 }
4098
4099 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004100 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4101 if (ret < 0) {
4102 wl1271_warning("could not allocate HLID - too many links");
4103 return -EBUSY;
4104 }
4105
4106 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004107 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004108 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004109 return 0;
4110}
4111
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004112void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004113{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004114 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004115 return;
4116
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004117 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004118 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004119 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004120 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004121 __clear_bit(hlid, &wl->ap_ps_map);
4122 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004123 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004124 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004125}
4126
4127static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4128 struct ieee80211_vif *vif,
4129 struct ieee80211_sta *sta)
4130{
4131 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004132 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004133 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004134 int ret = 0;
4135 u8 hlid;
4136
4137 mutex_lock(&wl->mutex);
4138
4139 if (unlikely(wl->state == WL1271_STATE_OFF))
4140 goto out;
4141
Eliad Peller536129c2011-10-05 11:55:45 +02004142 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004143 goto out;
4144
4145 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4146
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004147 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004148 if (ret < 0)
4149 goto out;
4150
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004151 wl_sta = (struct wl1271_station *)sta->drv_priv;
4152 hlid = wl_sta->hlid;
4153
Ido Yariva6208652011-03-01 15:14:41 +02004154 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004155 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004156 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004157
Eliad Peller1b92f152011-10-10 10:13:09 +02004158 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004159 if (ret < 0)
4160 goto out_sleep;
4161
Eliad Pellerb67476e2011-08-14 13:17:23 +03004162 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4163 if (ret < 0)
4164 goto out_sleep;
4165
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004166 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4167 if (ret < 0)
4168 goto out_sleep;
4169
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004170out_sleep:
4171 wl1271_ps_elp_sleep(wl);
4172
Arik Nemtsov409622e2011-02-23 00:22:29 +02004173out_free_sta:
4174 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004175 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004176
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004177out:
4178 mutex_unlock(&wl->mutex);
4179 return ret;
4180}
4181
4182static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4183 struct ieee80211_vif *vif,
4184 struct ieee80211_sta *sta)
4185{
4186 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004187 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004188 struct wl1271_station *wl_sta;
4189 int ret = 0, id;
4190
4191 mutex_lock(&wl->mutex);
4192
4193 if (unlikely(wl->state == WL1271_STATE_OFF))
4194 goto out;
4195
Eliad Peller536129c2011-10-05 11:55:45 +02004196 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004197 goto out;
4198
4199 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4200
4201 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004202 id = wl_sta->hlid;
4203 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004204 goto out;
4205
Ido Yariva6208652011-03-01 15:14:41 +02004206 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004207 if (ret < 0)
4208 goto out;
4209
Eliad Pellerc690ec82011-08-14 13:17:07 +03004210 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004211 if (ret < 0)
4212 goto out_sleep;
4213
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004214 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004215
4216out_sleep:
4217 wl1271_ps_elp_sleep(wl);
4218
4219out:
4220 mutex_unlock(&wl->mutex);
4221 return ret;
4222}
4223
Luciano Coelho4623ec72011-03-21 19:26:41 +02004224static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4225 struct ieee80211_vif *vif,
4226 enum ieee80211_ampdu_mlme_action action,
4227 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4228 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004229{
4230 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004231 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004232 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004233 u8 hlid, *ba_bitmap;
4234
4235 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4236 tid);
4237
4238 /* sanity check - the fields in FW are only 8bits wide */
4239 if (WARN_ON(tid > 0xFF))
4240 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004241
4242 mutex_lock(&wl->mutex);
4243
4244 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4245 ret = -EAGAIN;
4246 goto out;
4247 }
4248
Eliad Peller536129c2011-10-05 11:55:45 +02004249 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004250 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004251 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004252 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004253 struct wl1271_station *wl_sta;
4254
4255 wl_sta = (struct wl1271_station *)sta->drv_priv;
4256 hlid = wl_sta->hlid;
4257 ba_bitmap = &wl->links[hlid].ba_bitmap;
4258 } else {
4259 ret = -EINVAL;
4260 goto out;
4261 }
4262
Ido Yariva6208652011-03-01 15:14:41 +02004263 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004264 if (ret < 0)
4265 goto out;
4266
Shahar Levi70559a02011-05-22 16:10:22 +03004267 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4268 tid, action);
4269
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004270 switch (action) {
4271 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004272 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004273 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004274 break;
4275 }
4276
4277 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4278 ret = -EBUSY;
4279 wl1271_error("exceeded max RX BA sessions");
4280 break;
4281 }
4282
4283 if (*ba_bitmap & BIT(tid)) {
4284 ret = -EINVAL;
4285 wl1271_error("cannot enable RX BA session on active "
4286 "tid: %d", tid);
4287 break;
4288 }
4289
4290 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4291 hlid);
4292 if (!ret) {
4293 *ba_bitmap |= BIT(tid);
4294 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004295 }
4296 break;
4297
4298 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004299 if (!(*ba_bitmap & BIT(tid))) {
4300 ret = -EINVAL;
4301 wl1271_error("no active RX BA session on tid: %d",
4302 tid);
4303 break;
4304 }
4305
4306 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4307 hlid);
4308 if (!ret) {
4309 *ba_bitmap &= ~BIT(tid);
4310 wl->ba_rx_session_count--;
4311 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004312 break;
4313
4314 /*
4315 * The BA initiator session management in FW independently.
4316 * Falling break here on purpose for all TX APDU commands.
4317 */
4318 case IEEE80211_AMPDU_TX_START:
4319 case IEEE80211_AMPDU_TX_STOP:
4320 case IEEE80211_AMPDU_TX_OPERATIONAL:
4321 ret = -EINVAL;
4322 break;
4323
4324 default:
4325 wl1271_error("Incorrect ampdu action id=%x\n", action);
4326 ret = -EINVAL;
4327 }
4328
4329 wl1271_ps_elp_sleep(wl);
4330
4331out:
4332 mutex_unlock(&wl->mutex);
4333
4334 return ret;
4335}
4336
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004337static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4338 struct ieee80211_vif *vif,
4339 const struct cfg80211_bitrate_mask *mask)
4340{
Eliad Peller83587502011-10-10 10:12:53 +02004341 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004342 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004343 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004344
4345 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4346 mask->control[NL80211_BAND_2GHZ].legacy,
4347 mask->control[NL80211_BAND_5GHZ].legacy);
4348
4349 mutex_lock(&wl->mutex);
4350
4351 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004352 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004353 wl1271_tx_enabled_rates_get(wl,
4354 mask->control[i].legacy,
4355 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004356
4357 if (unlikely(wl->state == WL1271_STATE_OFF))
4358 goto out;
4359
4360 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4361 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4362
4363 ret = wl1271_ps_elp_wakeup(wl);
4364 if (ret < 0)
4365 goto out;
4366
4367 wl1271_set_band_rate(wl, wlvif);
4368 wlvif->basic_rate =
4369 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4370 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4371
4372 wl1271_ps_elp_sleep(wl);
4373 }
4374out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004375 mutex_unlock(&wl->mutex);
4376
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004377 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004378}
4379
Shahar Levi6d158ff2011-09-08 13:01:33 +03004380static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4381 struct ieee80211_channel_switch *ch_switch)
4382{
4383 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004384 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004385 int ret;
4386
4387 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4388
4389 mutex_lock(&wl->mutex);
4390
4391 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004392 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4393 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4394 ieee80211_chswitch_done(vif, false);
4395 }
4396 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004397 }
4398
4399 ret = wl1271_ps_elp_wakeup(wl);
4400 if (ret < 0)
4401 goto out;
4402
Eliad Peller52630c52011-10-10 10:13:08 +02004403 /* TODO: change mac80211 to pass vif as param */
4404 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4405 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004406
Eliad Peller52630c52011-10-10 10:13:08 +02004407 if (!ret)
4408 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4409 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004410
4411 wl1271_ps_elp_sleep(wl);
4412
4413out:
4414 mutex_unlock(&wl->mutex);
4415}
4416
Arik Nemtsov33437892011-04-26 23:35:39 +03004417static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4418{
4419 struct wl1271 *wl = hw->priv;
4420 bool ret = false;
4421
4422 mutex_lock(&wl->mutex);
4423
4424 if (unlikely(wl->state == WL1271_STATE_OFF))
4425 goto out;
4426
4427 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004428 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004429out:
4430 mutex_unlock(&wl->mutex);
4431
4432 return ret;
4433}
4434
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004435/* can't be const, mac80211 writes to this */
4436static struct ieee80211_rate wl1271_rates[] = {
4437 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004438 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4439 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004440 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004441 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4442 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004443 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4444 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004445 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4446 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004447 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4448 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004449 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4450 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004451 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4452 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004453 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4454 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004455 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004456 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4457 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004458 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004459 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4460 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004461 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004462 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4463 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004464 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004465 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4466 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004467 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004468 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4469 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004470 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004471 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4472 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004473 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004474 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4475 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004476};
4477
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004478/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004479static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004480 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004481 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004482 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4483 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4484 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004485 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004486 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4487 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4488 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004489 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004490 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4491 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4492 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004493 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004494};
4495
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004496/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004497static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004498 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004499 7, /* CONF_HW_RXTX_RATE_MCS7 */
4500 6, /* CONF_HW_RXTX_RATE_MCS6 */
4501 5, /* CONF_HW_RXTX_RATE_MCS5 */
4502 4, /* CONF_HW_RXTX_RATE_MCS4 */
4503 3, /* CONF_HW_RXTX_RATE_MCS3 */
4504 2, /* CONF_HW_RXTX_RATE_MCS2 */
4505 1, /* CONF_HW_RXTX_RATE_MCS1 */
4506 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004507
4508 11, /* CONF_HW_RXTX_RATE_54 */
4509 10, /* CONF_HW_RXTX_RATE_48 */
4510 9, /* CONF_HW_RXTX_RATE_36 */
4511 8, /* CONF_HW_RXTX_RATE_24 */
4512
4513 /* TI-specific rate */
4514 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4515
4516 7, /* CONF_HW_RXTX_RATE_18 */
4517 6, /* CONF_HW_RXTX_RATE_12 */
4518 3, /* CONF_HW_RXTX_RATE_11 */
4519 5, /* CONF_HW_RXTX_RATE_9 */
4520 4, /* CONF_HW_RXTX_RATE_6 */
4521 2, /* CONF_HW_RXTX_RATE_5_5 */
4522 1, /* CONF_HW_RXTX_RATE_2 */
4523 0 /* CONF_HW_RXTX_RATE_1 */
4524};
4525
Shahar Levie8b03a22010-10-13 16:09:39 +02004526/* 11n STA capabilities */
4527#define HW_RX_HIGHEST_RATE 72
4528
Shahar Levi00d20102010-11-08 11:20:10 +00004529#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004530 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4531 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004532 .ht_supported = true, \
4533 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4534 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4535 .mcs = { \
4536 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4537 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4538 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4539 }, \
4540}
4541
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004542/* can't be const, mac80211 writes to this */
4543static struct ieee80211_supported_band wl1271_band_2ghz = {
4544 .channels = wl1271_channels,
4545 .n_channels = ARRAY_SIZE(wl1271_channels),
4546 .bitrates = wl1271_rates,
4547 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004548 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004549};
4550
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004551/* 5 GHz data rates for WL1273 */
4552static struct ieee80211_rate wl1271_rates_5ghz[] = {
4553 { .bitrate = 60,
4554 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4555 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4556 { .bitrate = 90,
4557 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4558 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4559 { .bitrate = 120,
4560 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4561 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4562 { .bitrate = 180,
4563 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4564 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4565 { .bitrate = 240,
4566 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4567 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4568 { .bitrate = 360,
4569 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4570 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4571 { .bitrate = 480,
4572 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4573 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4574 { .bitrate = 540,
4575 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4576 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4577};
4578
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004579/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004580static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004581 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4582 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4583 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4584 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4585 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4586 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4587 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4588 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4589 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4590 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4591 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4592 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4593 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4594 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4595 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4596 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4597 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4598 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4599 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4600 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4601 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4602 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4603 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4604 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4605 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4606 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4607 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4608 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4609 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4610 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4611 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4612 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4613 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4614 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004615};
4616
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004617/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004618static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004619 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004620 7, /* CONF_HW_RXTX_RATE_MCS7 */
4621 6, /* CONF_HW_RXTX_RATE_MCS6 */
4622 5, /* CONF_HW_RXTX_RATE_MCS5 */
4623 4, /* CONF_HW_RXTX_RATE_MCS4 */
4624 3, /* CONF_HW_RXTX_RATE_MCS3 */
4625 2, /* CONF_HW_RXTX_RATE_MCS2 */
4626 1, /* CONF_HW_RXTX_RATE_MCS1 */
4627 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004628
4629 7, /* CONF_HW_RXTX_RATE_54 */
4630 6, /* CONF_HW_RXTX_RATE_48 */
4631 5, /* CONF_HW_RXTX_RATE_36 */
4632 4, /* CONF_HW_RXTX_RATE_24 */
4633
4634 /* TI-specific rate */
4635 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4636
4637 3, /* CONF_HW_RXTX_RATE_18 */
4638 2, /* CONF_HW_RXTX_RATE_12 */
4639 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4640 1, /* CONF_HW_RXTX_RATE_9 */
4641 0, /* CONF_HW_RXTX_RATE_6 */
4642 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4643 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4644 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4645};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004646
4647static struct ieee80211_supported_band wl1271_band_5ghz = {
4648 .channels = wl1271_channels_5ghz,
4649 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4650 .bitrates = wl1271_rates_5ghz,
4651 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004652 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004653};
4654
Tobias Klausera0ea9492010-05-20 10:38:11 +02004655static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004656 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4657 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4658};
4659
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004660static const struct ieee80211_ops wl1271_ops = {
4661 .start = wl1271_op_start,
4662 .stop = wl1271_op_stop,
4663 .add_interface = wl1271_op_add_interface,
4664 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004665 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004666#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004667 .suspend = wl1271_op_suspend,
4668 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004669#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004670 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004671 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004672 .configure_filter = wl1271_op_configure_filter,
4673 .tx = wl1271_op_tx,
4674 .set_key = wl1271_op_set_key,
4675 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004676 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004677 .sched_scan_start = wl1271_op_sched_scan_start,
4678 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004679 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004680 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004681 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004682 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004683 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004684 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004685 .sta_add = wl1271_op_sta_add,
4686 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004687 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004688 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004689 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004690 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004691 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004692};
4693
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004694
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004695u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004696{
4697 u8 idx;
4698
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004699 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004700
4701 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4702 wl1271_error("Illegal RX rate from HW: %d", rate);
4703 return 0;
4704 }
4705
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004706 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004707 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4708 wl1271_error("Unsupported RX rate from HW: %d", rate);
4709 return 0;
4710 }
4711
4712 return idx;
4713}
4714
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004715static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4716 struct device_attribute *attr,
4717 char *buf)
4718{
4719 struct wl1271 *wl = dev_get_drvdata(dev);
4720 ssize_t len;
4721
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004722 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004723
4724 mutex_lock(&wl->mutex);
4725 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4726 wl->sg_enabled);
4727 mutex_unlock(&wl->mutex);
4728
4729 return len;
4730
4731}
4732
4733static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4734 struct device_attribute *attr,
4735 const char *buf, size_t count)
4736{
4737 struct wl1271 *wl = dev_get_drvdata(dev);
4738 unsigned long res;
4739 int ret;
4740
Luciano Coelho6277ed62011-04-01 17:49:54 +03004741 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004742 if (ret < 0) {
4743 wl1271_warning("incorrect value written to bt_coex_mode");
4744 return count;
4745 }
4746
4747 mutex_lock(&wl->mutex);
4748
4749 res = !!res;
4750
4751 if (res == wl->sg_enabled)
4752 goto out;
4753
4754 wl->sg_enabled = res;
4755
4756 if (wl->state == WL1271_STATE_OFF)
4757 goto out;
4758
Ido Yariva6208652011-03-01 15:14:41 +02004759 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004760 if (ret < 0)
4761 goto out;
4762
4763 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4764 wl1271_ps_elp_sleep(wl);
4765
4766 out:
4767 mutex_unlock(&wl->mutex);
4768 return count;
4769}
4770
4771static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4772 wl1271_sysfs_show_bt_coex_state,
4773 wl1271_sysfs_store_bt_coex_state);
4774
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004775static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4776 struct device_attribute *attr,
4777 char *buf)
4778{
4779 struct wl1271 *wl = dev_get_drvdata(dev);
4780 ssize_t len;
4781
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004782 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004783
4784 mutex_lock(&wl->mutex);
4785 if (wl->hw_pg_ver >= 0)
4786 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4787 else
4788 len = snprintf(buf, len, "n/a\n");
4789 mutex_unlock(&wl->mutex);
4790
4791 return len;
4792}
4793
Gery Kahn6f07b722011-07-18 14:21:49 +03004794static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004795 wl1271_sysfs_show_hw_pg_ver, NULL);
4796
Ido Yariv95dac04f2011-06-06 14:57:06 +03004797static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4798 struct bin_attribute *bin_attr,
4799 char *buffer, loff_t pos, size_t count)
4800{
4801 struct device *dev = container_of(kobj, struct device, kobj);
4802 struct wl1271 *wl = dev_get_drvdata(dev);
4803 ssize_t len;
4804 int ret;
4805
4806 ret = mutex_lock_interruptible(&wl->mutex);
4807 if (ret < 0)
4808 return -ERESTARTSYS;
4809
4810 /* Let only one thread read the log at a time, blocking others */
4811 while (wl->fwlog_size == 0) {
4812 DEFINE_WAIT(wait);
4813
4814 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4815 &wait,
4816 TASK_INTERRUPTIBLE);
4817
4818 if (wl->fwlog_size != 0) {
4819 finish_wait(&wl->fwlog_waitq, &wait);
4820 break;
4821 }
4822
4823 mutex_unlock(&wl->mutex);
4824
4825 schedule();
4826 finish_wait(&wl->fwlog_waitq, &wait);
4827
4828 if (signal_pending(current))
4829 return -ERESTARTSYS;
4830
4831 ret = mutex_lock_interruptible(&wl->mutex);
4832 if (ret < 0)
4833 return -ERESTARTSYS;
4834 }
4835
4836 /* Check if the fwlog is still valid */
4837 if (wl->fwlog_size < 0) {
4838 mutex_unlock(&wl->mutex);
4839 return 0;
4840 }
4841
4842 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4843 len = min(count, (size_t)wl->fwlog_size);
4844 wl->fwlog_size -= len;
4845 memcpy(buffer, wl->fwlog, len);
4846
4847 /* Make room for new messages */
4848 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4849
4850 mutex_unlock(&wl->mutex);
4851
4852 return len;
4853}
4854
4855static struct bin_attribute fwlog_attr = {
4856 .attr = {.name = "fwlog", .mode = S_IRUSR},
4857 .read = wl1271_sysfs_read_fwlog,
4858};
4859
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004860static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004861{
4862 int ret;
4863
4864 if (wl->mac80211_registered)
4865 return 0;
4866
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004867 ret = wl1271_fetch_nvs(wl);
4868 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004869 /* NOTE: The wl->nvs->nvs element must be first, in
4870 * order to simplify the casting, we assume it is at
4871 * the beginning of the wl->nvs structure.
4872 */
4873 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004874
4875 wl->mac_addr[0] = nvs_ptr[11];
4876 wl->mac_addr[1] = nvs_ptr[10];
4877 wl->mac_addr[2] = nvs_ptr[6];
4878 wl->mac_addr[3] = nvs_ptr[5];
4879 wl->mac_addr[4] = nvs_ptr[4];
4880 wl->mac_addr[5] = nvs_ptr[3];
4881 }
4882
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004883 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4884
4885 ret = ieee80211_register_hw(wl->hw);
4886 if (ret < 0) {
4887 wl1271_error("unable to register mac80211 hw: %d", ret);
4888 return ret;
4889 }
4890
4891 wl->mac80211_registered = true;
4892
Eliad Pellerd60080a2010-11-24 12:53:16 +02004893 wl1271_debugfs_init(wl);
4894
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004895 register_netdevice_notifier(&wl1271_dev_notifier);
4896
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004897 wl1271_notice("loaded");
4898
4899 return 0;
4900}
4901
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004902static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004903{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004904 if (wl->state == WL1271_STATE_PLT)
Ido Yarivf3df1332012-01-11 09:42:39 +02004905 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004906
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004907 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004908 ieee80211_unregister_hw(wl->hw);
4909 wl->mac80211_registered = false;
4910
4911}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004912
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004913static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004914{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004915 static const u32 cipher_suites[] = {
4916 WLAN_CIPHER_SUITE_WEP40,
4917 WLAN_CIPHER_SUITE_WEP104,
4918 WLAN_CIPHER_SUITE_TKIP,
4919 WLAN_CIPHER_SUITE_CCMP,
4920 WL1271_CIPHER_SUITE_GEM,
4921 };
4922
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004923 /* The tx descriptor buffer and the TKIP space. */
4924 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4925 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004926
4927 /* unit us */
4928 /* FIXME: find a proper value */
4929 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004930 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004931
4932 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004933 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004934 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004935 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004936 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004937 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004938 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004939 IEEE80211_HW_AP_LINK_PS |
4940 IEEE80211_HW_AMPDU_AGGREGATION |
4941 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004942
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004943 wl->hw->wiphy->cipher_suites = cipher_suites;
4944 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4945
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004946 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004947 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4948 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004949 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004950 wl->hw->wiphy->max_sched_scan_ssids = 16;
4951 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004952 /*
4953 * Maximum length of elements in scanning probe request templates
4954 * should be the maximum length possible for a template, without
4955 * the IEEE80211 header of the template
4956 */
Eliad Peller154037d2011-08-14 13:17:12 +03004957 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004958 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004959
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004960 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4961 sizeof(struct ieee80211_header);
4962
Eliad Peller1ec23f72011-08-25 14:26:54 +03004963 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4964
Luciano Coelho4a31c112011-03-21 23:16:14 +02004965 /* make sure all our channels fit in the scanned_ch bitmask */
4966 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4967 ARRAY_SIZE(wl1271_channels_5ghz) >
4968 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004969 /*
4970 * We keep local copies of the band structs because we need to
4971 * modify them on a per-device basis.
4972 */
4973 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4974 sizeof(wl1271_band_2ghz));
4975 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4976 sizeof(wl1271_band_5ghz));
4977
4978 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4979 &wl->bands[IEEE80211_BAND_2GHZ];
4980 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4981 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004982
Kalle Valo12bd8942010-03-18 12:26:33 +02004983 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004984 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004985
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004986 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4987
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02004988 /* the FW answers probe-requests in AP-mode */
4989 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
4990 wl->hw->wiphy->probe_resp_offload =
4991 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
4992 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
4993 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
4994
Felipe Balbia390e852011-10-06 10:07:44 +03004995 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004996
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004997 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004998 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004999
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005000 wl->hw->max_rx_aggregation_subframes = 8;
5001
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005002 return 0;
5003}
5004
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005005#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005006
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005007static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005008{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005009 struct ieee80211_hw *hw;
5010 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005011 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005012 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005013
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005014 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005015
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005016 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5017 if (!hw) {
5018 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005019 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005020 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005021 }
5022
5023 wl = hw->priv;
5024 memset(wl, 0, sizeof(*wl));
5025
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005026 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005027 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005028
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005029 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005030
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005031 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005032 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005033 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5034
Ido Yariva6208652011-03-01 15:14:41 +02005035 skb_queue_head_init(&wl->deferred_rx_queue);
5036 skb_queue_head_init(&wl->deferred_tx_queue);
5037
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005038 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005039 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005040 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5041 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5042 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005043
Eliad Peller92ef8962011-06-07 12:50:46 +03005044 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5045 if (!wl->freezable_wq) {
5046 ret = -ENOMEM;
5047 goto err_hw;
5048 }
5049
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005050 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005051 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005052 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005053 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005054 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005055 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005056 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005057 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005058 wl->ap_ps_map = 0;
5059 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005060 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005061 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005062 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005063 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005064 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005065 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005066 wl->fwlog_size = 0;
5067 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005068
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005069 /* The system link is always allocated */
5070 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5071
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005072 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005073 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005074 wl->tx_frames[i] = NULL;
5075
5076 spin_lock_init(&wl->wl_lock);
5077
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005078 wl->state = WL1271_STATE_OFF;
5079 mutex_init(&wl->mutex);
5080
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005081 /* Apply default driver configuration. */
5082 wl1271_conf_init(wl);
5083
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005084 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5085 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5086 if (!wl->aggr_buf) {
5087 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005088 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005089 }
5090
Ido Yariv990f5de2011-03-31 10:06:59 +02005091 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5092 if (!wl->dummy_packet) {
5093 ret = -ENOMEM;
5094 goto err_aggr;
5095 }
5096
Ido Yariv95dac04f2011-06-06 14:57:06 +03005097 /* Allocate one page for the FW log */
5098 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5099 if (!wl->fwlog) {
5100 ret = -ENOMEM;
5101 goto err_dummy_packet;
5102 }
5103
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005104 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005105
Ido Yariv990f5de2011-03-31 10:06:59 +02005106err_dummy_packet:
5107 dev_kfree_skb(wl->dummy_packet);
5108
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005109err_aggr:
5110 free_pages((unsigned long)wl->aggr_buf, order);
5111
Eliad Peller92ef8962011-06-07 12:50:46 +03005112err_wq:
5113 destroy_workqueue(wl->freezable_wq);
5114
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005115err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005116 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005117 ieee80211_free_hw(hw);
5118
5119err_hw_alloc:
5120
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005121 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005122}
5123
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005124static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005125{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005126 /* Unblock any fwlog readers */
5127 mutex_lock(&wl->mutex);
5128 wl->fwlog_size = -1;
5129 wake_up_interruptible_all(&wl->fwlog_waitq);
5130 mutex_unlock(&wl->mutex);
5131
Felipe Balbif79f8902011-10-06 13:05:25 +03005132 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005133
Felipe Balbif79f8902011-10-06 13:05:25 +03005134 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005135
Felipe Balbif79f8902011-10-06 13:05:25 +03005136 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005137 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005138 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005139 free_pages((unsigned long)wl->aggr_buf,
5140 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005141
5142 wl1271_debugfs_exit(wl);
5143
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005144 vfree(wl->fw);
5145 wl->fw = NULL;
5146 kfree(wl->nvs);
5147 wl->nvs = NULL;
5148
5149 kfree(wl->fw_status);
5150 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005151 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005152
5153 ieee80211_free_hw(wl->hw);
5154
5155 return 0;
5156}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005157
Felipe Balbia390e852011-10-06 10:07:44 +03005158static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5159{
5160 struct wl1271 *wl = cookie;
5161 unsigned long flags;
5162
5163 wl1271_debug(DEBUG_IRQ, "IRQ");
5164
5165 /* complete the ELP completion */
5166 spin_lock_irqsave(&wl->wl_lock, flags);
5167 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5168 if (wl->elp_compl) {
5169 complete(wl->elp_compl);
5170 wl->elp_compl = NULL;
5171 }
5172
5173 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5174 /* don't enqueue a work right now. mark it as pending */
5175 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5176 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5177 disable_irq_nosync(wl->irq);
5178 pm_wakeup_event(wl->dev, 0);
5179 spin_unlock_irqrestore(&wl->wl_lock, flags);
5180 return IRQ_HANDLED;
5181 }
5182 spin_unlock_irqrestore(&wl->wl_lock, flags);
5183
5184 return IRQ_WAKE_THREAD;
5185}
5186
Felipe Balbice2a2172011-10-05 14:12:55 +03005187static int __devinit wl12xx_probe(struct platform_device *pdev)
5188{
Felipe Balbia390e852011-10-06 10:07:44 +03005189 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5190 struct ieee80211_hw *hw;
5191 struct wl1271 *wl;
5192 unsigned long irqflags;
5193 int ret = -ENODEV;
5194
5195 hw = wl1271_alloc_hw();
5196 if (IS_ERR(hw)) {
5197 wl1271_error("can't allocate hw");
5198 ret = PTR_ERR(hw);
5199 goto out;
5200 }
5201
5202 wl = hw->priv;
5203 wl->irq = platform_get_irq(pdev, 0);
5204 wl->ref_clock = pdata->board_ref_clock;
5205 wl->tcxo_clock = pdata->board_tcxo_clock;
5206 wl->platform_quirks = pdata->platform_quirks;
5207 wl->set_power = pdata->set_power;
5208 wl->dev = &pdev->dev;
5209 wl->if_ops = pdata->ops;
5210
5211 platform_set_drvdata(pdev, wl);
5212
5213 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5214 irqflags = IRQF_TRIGGER_RISING;
5215 else
5216 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5217
5218 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5219 irqflags,
5220 pdev->name, wl);
5221 if (ret < 0) {
5222 wl1271_error("request_irq() failed: %d", ret);
5223 goto out_free_hw;
5224 }
5225
5226 ret = enable_irq_wake(wl->irq);
5227 if (!ret) {
5228 wl->irq_wake_enabled = true;
5229 device_init_wakeup(wl->dev, 1);
5230 if (pdata->pwr_in_suspend)
5231 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5232
5233 }
5234 disable_irq(wl->irq);
5235
5236 ret = wl1271_init_ieee80211(wl);
5237 if (ret)
5238 goto out_irq;
5239
5240 ret = wl1271_register_hw(wl);
5241 if (ret)
5242 goto out_irq;
5243
Felipe Balbif79f8902011-10-06 13:05:25 +03005244 /* Create sysfs file to control bt coex state */
5245 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5246 if (ret < 0) {
5247 wl1271_error("failed to create sysfs file bt_coex_state");
5248 goto out_irq;
5249 }
5250
5251 /* Create sysfs file to get HW PG version */
5252 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5253 if (ret < 0) {
5254 wl1271_error("failed to create sysfs file hw_pg_ver");
5255 goto out_bt_coex_state;
5256 }
5257
5258 /* Create sysfs file for the FW log */
5259 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5260 if (ret < 0) {
5261 wl1271_error("failed to create sysfs file fwlog");
5262 goto out_hw_pg_ver;
5263 }
5264
Felipe Balbice2a2172011-10-05 14:12:55 +03005265 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005266
Felipe Balbif79f8902011-10-06 13:05:25 +03005267out_hw_pg_ver:
5268 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5269
5270out_bt_coex_state:
5271 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5272
Felipe Balbia390e852011-10-06 10:07:44 +03005273out_irq:
5274 free_irq(wl->irq, wl);
5275
5276out_free_hw:
5277 wl1271_free_hw(wl);
5278
5279out:
5280 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005281}
5282
5283static int __devexit wl12xx_remove(struct platform_device *pdev)
5284{
Felipe Balbia390e852011-10-06 10:07:44 +03005285 struct wl1271 *wl = platform_get_drvdata(pdev);
5286
5287 if (wl->irq_wake_enabled) {
5288 device_init_wakeup(wl->dev, 0);
5289 disable_irq_wake(wl->irq);
5290 }
5291 wl1271_unregister_hw(wl);
5292 free_irq(wl->irq, wl);
5293 wl1271_free_hw(wl);
5294
Felipe Balbice2a2172011-10-05 14:12:55 +03005295 return 0;
5296}
5297
5298static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005299 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005300 { } /* Terminating Entry */
5301};
5302MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5303
5304static struct platform_driver wl12xx_driver = {
5305 .probe = wl12xx_probe,
5306 .remove = __devexit_p(wl12xx_remove),
5307 .id_table = wl12xx_id_table,
5308 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005309 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005310 .owner = THIS_MODULE,
5311 }
5312};
5313
5314static int __init wl12xx_init(void)
5315{
5316 return platform_driver_register(&wl12xx_driver);
5317}
5318module_init(wl12xx_init);
5319
5320static void __exit wl12xx_exit(void)
5321{
5322 platform_driver_unregister(&wl12xx_driver);
5323}
5324module_exit(wl12xx_exit);
5325
Guy Eilam491bbd62011-01-12 10:33:29 +01005326u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005327EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005328module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005329MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5330
Ido Yariv95dac04f2011-06-06 14:57:06 +03005331module_param_named(fwlog, fwlog_param, charp, 0);
5332MODULE_PARM_DESC(keymap,
5333 "FW logger options: continuous, ondemand, dbgpins or disable");
5334
Eliad Peller2a5bff02011-08-25 18:10:59 +03005335module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5336MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5337
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005338MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005339MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005340MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");