blob: c10940703e8c904c214660144f2525b065761697 [file] [log] [blame]
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02001
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002/*
3 * This file is part of wl1271
4 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02005 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03006 *
7 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030026#include <linux/firmware.h>
27#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030028#include <linux/spi/spi.h>
29#include <linux/crc32.h>
30#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030031#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020032#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020034#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030035#include <linux/sched.h>
Felipe Balbia390e852011-10-06 10:07:44 +030036#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037
Shahar Levi00d20102010-11-08 11:20:10 +000038#include "wl12xx.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030039#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030040#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000041#include "reg.h"
42#include "io.h"
43#include "event.h"
44#include "tx.h"
45#include "rx.h"
46#include "ps.h"
47#include "init.h"
48#include "debugfs.h"
49#include "cmd.h"
50#include "boot.h"
51#include "testmode.h"
52#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030053
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020054#define WL1271_BOOT_RETRIES 3
55
Juuso Oikarinen8a080482009-10-13 12:47:44 +030056static struct conf_drv_settings default_conf = {
57 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030058 .params = {
59 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
60 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
61 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
62 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
63 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
64 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
65 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
66 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
67 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
68 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
69 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
70 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
71 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
72 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
73 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
74 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
75 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
76 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
77 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
78 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
79 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
80 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
81 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
82 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
83 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
84 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
85 /* active scan params */
86 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
87 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
88 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
89 /* passive scan params */
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
91 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
92 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
93 /* passive scan in dual antenna params */
94 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
95 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
96 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
97 /* general params */
98 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
99 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
100 [CONF_SG_BEACON_MISS_PERCENT] = 60,
101 [CONF_SG_DHCP_TIME] = 5000,
102 [CONF_SG_RXT] = 1200,
103 [CONF_SG_TXT] = 1000,
104 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
105 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
106 [CONF_SG_HV3_MAX_SERVED] = 6,
107 [CONF_SG_PS_POLL_TIMEOUT] = 10,
108 [CONF_SG_UPSD_TIMEOUT] = 10,
109 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
110 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
111 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
112 /* AP params */
113 [CONF_AP_BEACON_MISS_TX] = 3,
114 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
115 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
116 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
117 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
118 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Eliad Peller26612c42012-01-31 17:54:43 +0200119 /* CTS Diluting params */
120 [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
121 [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300122 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200123 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300124 },
125 .rx = {
126 .rx_msdu_life_time = 512000,
127 .packet_detection_threshold = 0,
128 .ps_poll_timeout = 15,
129 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300130 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200131 .rx_cca_threshold = 0,
132 .irq_blk_threshold = 0xFFFF,
133 .irq_pkt_threshold = 0,
134 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
136 },
137 .tx = {
138 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200139 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300140 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300141 .short_retry_limit = 10,
142 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200143 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300144 },
145 .ac_conf_count = 4,
146 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200147 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300148 .ac = CONF_TX_AC_BE,
149 .cw_min = 15,
150 .cw_max = 63,
151 .aifsn = 3,
152 .tx_op_limit = 0,
153 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200154 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300155 .ac = CONF_TX_AC_BK,
156 .cw_min = 15,
157 .cw_max = 63,
158 .aifsn = 7,
159 .tx_op_limit = 0,
160 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200161 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300162 .ac = CONF_TX_AC_VI,
163 .cw_min = 15,
164 .cw_max = 63,
165 .aifsn = CONF_TX_AIFS_PIFS,
166 .tx_op_limit = 3008,
167 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200168 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300169 .ac = CONF_TX_AC_VO,
170 .cw_min = 15,
171 .cw_max = 63,
172 .aifsn = CONF_TX_AIFS_PIFS,
173 .tx_op_limit = 1504,
174 },
175 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300176 .max_tx_retries = 100,
177 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200178 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300179 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200180 [CONF_TX_AC_BE] = {
181 .queue_id = CONF_TX_AC_BE,
182 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300183 .tsid = CONF_TX_AC_BE,
184 .ps_scheme = CONF_PS_SCHEME_LEGACY,
185 .ack_policy = CONF_ACK_POLICY_LEGACY,
186 .apsd_conf = {0, 0},
187 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200188 [CONF_TX_AC_BK] = {
189 .queue_id = CONF_TX_AC_BK,
190 .channel_type = CONF_CHANNEL_TYPE_EDCF,
191 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300192 .ps_scheme = CONF_PS_SCHEME_LEGACY,
193 .ack_policy = CONF_ACK_POLICY_LEGACY,
194 .apsd_conf = {0, 0},
195 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200196 [CONF_TX_AC_VI] = {
197 .queue_id = CONF_TX_AC_VI,
198 .channel_type = CONF_CHANNEL_TYPE_EDCF,
199 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .ps_scheme = CONF_PS_SCHEME_LEGACY,
201 .ack_policy = CONF_ACK_POLICY_LEGACY,
202 .apsd_conf = {0, 0},
203 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200204 [CONF_TX_AC_VO] = {
205 .queue_id = CONF_TX_AC_VO,
206 .channel_type = CONF_CHANNEL_TYPE_EDCF,
207 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300208 .ps_scheme = CONF_PS_SCHEME_LEGACY,
209 .ack_policy = CONF_ACK_POLICY_LEGACY,
210 .apsd_conf = {0, 0},
211 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300212 },
213 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200214 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300215 .tx_compl_threshold = 4,
216 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
217 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200218 .tmpl_short_retry_limit = 10,
219 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 },
221 .conn = {
222 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300223 .listen_interval = 1,
Eyal Shapiradae728f2012-02-02 12:03:39 +0200224 .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM,
225 .suspend_listen_interval = 3,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300226 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300227 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300228 .bcn_filt_ie = {
229 [0] = {
230 .ie = WLAN_EID_CHANNEL_SWITCH,
231 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300232 },
233 [1] = {
234 .ie = WLAN_EID_HT_INFORMATION,
235 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
236 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200238 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300239 .bss_lose_timeout = 100,
240 .beacon_rx_timeout = 10000,
241 .broadcast_timeout = 20000,
242 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300243 .ps_poll_threshold = 10,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300244 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200245 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300246 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300247 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200248 .psm_entry_nullfunc_retries = 3,
Eyal Shapiraf1d63a52012-01-31 11:57:21 +0200249 .dynamic_ps_timeout = 100,
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +0200250 .forced_ps = false,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300251 .keep_alive_interval = 55000,
252 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300253 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200254 .itrim = {
255 .enable = false,
256 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200257 },
258 .pm_config = {
259 .host_clk_settling_time = 5000,
260 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300261 },
262 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300263 .trigger_pacing = 1,
264 .avg_weight_rssi_beacon = 20,
265 .avg_weight_rssi_data = 10,
266 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100267 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200268 },
269 .scan = {
270 .min_dwell_time_active = 7500,
271 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100272 .min_dwell_time_passive = 100000,
273 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200274 .num_probe_reqs = 2,
Eyal Shapirad647f2d2012-02-02 13:54:28 +0200275 .split_scan_timeout = 50000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200276 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300277 .sched_scan = {
278 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300279 .min_dwell_time_active = 30,
280 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300281 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300282 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300283 .num_probe_reqs = 2,
284 .rssi_threshold = -90,
285 .snr_threshold = 0,
286 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200287 .rf = {
288 .tx_per_channel_power_compensation_2 = {
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 },
291 .tx_per_channel_power_compensation_5 = {
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 },
296 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100297 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300298 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100299 .tx_ba_win_size = 64,
300 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300301 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100302 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200303 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200304 .num_stations = 1,
305 .ssid_profiles = 1,
306 .rx_block_num = 70,
307 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300308 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200309 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200310 .min_req_rx_blocks = 22,
311 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200312 },
313 .mem_wl128x = {
314 .num_stations = 1,
315 .ssid_profiles = 1,
316 .rx_block_num = 40,
317 .tx_min_block_num = 40,
318 .dynamic_memory = 1,
319 .min_req_tx_blocks = 45,
320 .min_req_rx_blocks = 22,
321 .tx_min = 27,
322 },
Shahar Leviff868432011-04-11 15:41:46 +0300323 .fm_coex = {
324 .enable = true,
325 .swallow_period = 5,
326 .n_divider_fref_set_1 = 0xff, /* default */
327 .n_divider_fref_set_2 = 12,
328 .m_divider_fref_set_1 = 148,
329 .m_divider_fref_set_2 = 0xffff, /* default */
330 .coex_pll_stabilization_time = 0xffffffff, /* default */
331 .ldo_stabilization_time = 0xffff, /* default */
332 .fm_disturbed_band_margin = 0xff, /* default */
333 .swallow_clk_diff = 0xff, /* default */
334 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300335 .rx_streaming = {
336 .duration = 150,
337 .queues = 0x1,
338 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300339 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300340 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300341 .fwlog = {
342 .mode = WL12XX_FWLOG_ON_DEMAND,
343 .mem_blocks = 2,
344 .severity = 0,
345 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
346 .output = WL12XX_FWLOG_OUTPUT_HOST,
347 .threshold = 0,
348 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300349 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300350 .rate = {
351 .rate_retry_score = 32000,
352 .per_add = 8192,
353 .per_th1 = 2048,
354 .per_th2 = 4096,
355 .max_per = 8100,
356 .inverse_curiosity_factor = 5,
357 .tx_fail_low_th = 4,
358 .tx_fail_high_th = 10,
359 .per_alpha_shift = 4,
360 .per_add_shift = 13,
361 .per_beta1_shift = 10,
362 .per_beta2_shift = 8,
363 .rate_check_up = 2,
364 .rate_check_down = 12,
365 .rate_retry_policy = {
366 0x00, 0x00, 0x00, 0x00, 0x00,
367 0x00, 0x00, 0x00, 0x00, 0x00,
368 0x00, 0x00, 0x00,
369 },
370 },
Eliad Peller94877752011-08-28 15:11:56 +0300371 .hangover = {
372 .recover_time = 0,
373 .hangover_period = 20,
374 .dynamic_mode = 1,
375 .early_termination_mode = 1,
376 .max_period = 20,
377 .min_period = 1,
378 .increase_delta = 1,
379 .decrease_delta = 2,
380 .quiet_time = 4,
381 .increase_time = 1,
382 .window_size = 16,
383 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300384};
385
Ido Yariv95dac04f2011-06-06 14:57:06 +0300386static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300387static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300388
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300389static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200390 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300391 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200392static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200393static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200394
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200395static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300396static LIST_HEAD(wl_list);
397
Eliad Pellerba8447f2011-10-10 10:13:00 +0200398static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
399 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300400{
401 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200402
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300403 if (operstate != IF_OPER_UP)
404 return 0;
405
Eliad Peller8181aec2011-10-10 10:13:04 +0200406 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300407 return 0;
408
Eliad Peller154da672011-10-05 11:55:53 +0200409 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300410 if (ret < 0)
411 return ret;
412
Eliad Peller0603d892011-10-05 11:55:51 +0200413 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300414
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300415 wl1271_info("Association completed.");
416 return 0;
417}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300418static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
419 void *arg)
420{
421 struct net_device *dev = arg;
422 struct wireless_dev *wdev;
423 struct wiphy *wiphy;
424 struct ieee80211_hw *hw;
425 struct wl1271 *wl;
426 struct wl1271 *wl_temp;
Eliad Pellerba8447f2011-10-10 10:13:00 +0200427 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300428 int ret = 0;
429
430 /* Check that this notification is for us. */
431 if (what != NETDEV_CHANGE)
432 return NOTIFY_DONE;
433
434 wdev = dev->ieee80211_ptr;
435 if (wdev == NULL)
436 return NOTIFY_DONE;
437
438 wiphy = wdev->wiphy;
439 if (wiphy == NULL)
440 return NOTIFY_DONE;
441
442 hw = wiphy_priv(wiphy);
443 if (hw == NULL)
444 return NOTIFY_DONE;
445
446 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200447 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300448 list_for_each_entry(wl, &wl_list, list) {
449 if (wl == wl_temp)
450 break;
451 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200452 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300453 if (wl != wl_temp)
454 return NOTIFY_DONE;
455
456 mutex_lock(&wl->mutex);
457
458 if (wl->state == WL1271_STATE_OFF)
459 goto out;
460
Eliad Peller6ab70912011-12-18 20:25:45 +0200461 if (dev->operstate != IF_OPER_UP)
462 goto out;
463 /*
464 * The correct behavior should be just getting the appropriate wlvif
465 * from the given dev, but currently we don't have a mac80211
466 * interface for it.
467 */
Eliad Pellerba8447f2011-10-10 10:13:00 +0200468 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller6ab70912011-12-18 20:25:45 +0200469 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
470
Eliad Pellerba8447f2011-10-10 10:13:00 +0200471 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
472 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300473
Eliad Pellerba8447f2011-10-10 10:13:00 +0200474 ret = wl1271_ps_elp_wakeup(wl);
475 if (ret < 0)
476 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300477
Eliad Peller6ab70912011-12-18 20:25:45 +0200478 wl1271_check_operstate(wl, wlvif,
479 ieee80211_get_operstate(vif));
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300480
Eliad Pellerba8447f2011-10-10 10:13:00 +0200481 wl1271_ps_elp_sleep(wl);
482 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300483out:
484 mutex_unlock(&wl->mutex);
485
486 return NOTIFY_OK;
487}
488
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100489static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200490 struct regulatory_request *request)
491{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100492 struct ieee80211_supported_band *band;
493 struct ieee80211_channel *ch;
494 int i;
495
496 band = wiphy->bands[IEEE80211_BAND_5GHZ];
497 for (i = 0; i < band->n_channels; i++) {
498 ch = &band->channels[i];
499 if (ch->flags & IEEE80211_CHAN_DISABLED)
500 continue;
501
502 if (ch->flags & IEEE80211_CHAN_RADAR)
503 ch->flags |= IEEE80211_CHAN_NO_IBSS |
504 IEEE80211_CHAN_PASSIVE_SCAN;
505
506 }
507
508 return 0;
509}
510
Eliad Peller9eb599e2011-10-10 10:12:59 +0200511static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
512 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300513{
514 int ret = 0;
515
516 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200517 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300518 if (ret < 0)
519 goto out;
520
521 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200522 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300523 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200524 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300525out:
526 return ret;
527}
528
529/*
530 * this function is being called when the rx_streaming interval
531 * has beed changed or rx_streaming should be disabled
532 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200533int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300534{
535 int ret = 0;
536 int period = wl->conf.rx_streaming.interval;
537
538 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200539 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300540 goto out;
541
542 /* reconfigure/disable according to new streaming_period */
543 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200544 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300545 (wl->conf.rx_streaming.always ||
546 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200547 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300548 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200549 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300550 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200551 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300552 }
553out:
554 return ret;
555}
556
557static void wl1271_rx_streaming_enable_work(struct work_struct *work)
558{
559 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200560 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
561 rx_streaming_enable_work);
562 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300563
564 mutex_lock(&wl->mutex);
565
Eliad Peller0744bdb2011-10-10 10:13:05 +0200566 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200567 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300568 (!wl->conf.rx_streaming.always &&
569 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
570 goto out;
571
572 if (!wl->conf.rx_streaming.interval)
573 goto out;
574
575 ret = wl1271_ps_elp_wakeup(wl);
576 if (ret < 0)
577 goto out;
578
Eliad Peller9eb599e2011-10-10 10:12:59 +0200579 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300580 if (ret < 0)
581 goto out_sleep;
582
583 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200584 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300585 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
586
587out_sleep:
588 wl1271_ps_elp_sleep(wl);
589out:
590 mutex_unlock(&wl->mutex);
591}
592
593static void wl1271_rx_streaming_disable_work(struct work_struct *work)
594{
595 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200596 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
597 rx_streaming_disable_work);
598 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300599
600 mutex_lock(&wl->mutex);
601
Eliad Peller0744bdb2011-10-10 10:13:05 +0200602 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300603 goto out;
604
605 ret = wl1271_ps_elp_wakeup(wl);
606 if (ret < 0)
607 goto out;
608
Eliad Peller9eb599e2011-10-10 10:12:59 +0200609 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300610 if (ret)
611 goto out_sleep;
612
613out_sleep:
614 wl1271_ps_elp_sleep(wl);
615out:
616 mutex_unlock(&wl->mutex);
617}
618
619static void wl1271_rx_streaming_timer(unsigned long data)
620{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200621 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
622 struct wl1271 *wl = wlvif->wl;
623 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300624}
625
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300626static void wl1271_conf_init(struct wl1271 *wl)
627{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300628
629 /*
630 * This function applies the default configuration to the driver. This
631 * function is invoked upon driver load (spi probe.)
632 *
633 * The configuration is stored in a run-time structure in order to
634 * facilitate for run-time adjustment of any of the parameters. Making
635 * changes to the configuration structure will apply the new values on
636 * the next interface up (wl1271_op_start.)
637 */
638
639 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300640 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300641
Ido Yariv95dac04f2011-06-06 14:57:06 +0300642 /* Adjust settings according to optional module parameters */
643 if (fwlog_param) {
644 if (!strcmp(fwlog_param, "continuous")) {
645 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
646 } else if (!strcmp(fwlog_param, "ondemand")) {
647 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
648 } else if (!strcmp(fwlog_param, "dbgpins")) {
649 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
650 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
651 } else if (!strcmp(fwlog_param, "disable")) {
652 wl->conf.fwlog.mem_blocks = 0;
653 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
654 } else {
655 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
656 }
657 }
658}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300659
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300660static int wl1271_plt_init(struct wl1271 *wl)
661{
Eliad Peller188e7f52011-12-06 12:15:06 +0200662 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300663
Shahar Levi49d750ca2011-03-06 16:32:09 +0200664 if (wl->chip.id == CHIP_ID_1283_PG20)
665 ret = wl128x_cmd_general_parms(wl);
666 else
667 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200668 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200669 return ret;
670
Shahar Levi49d750ca2011-03-06 16:32:09 +0200671 if (wl->chip.id == CHIP_ID_1283_PG20)
672 ret = wl128x_cmd_radio_parms(wl);
673 else
674 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200675 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200676 return ret;
677
Shahar Levi49d750ca2011-03-06 16:32:09 +0200678 if (wl->chip.id != CHIP_ID_1283_PG20) {
679 ret = wl1271_cmd_ext_radio_parms(wl);
680 if (ret < 0)
681 return ret;
682 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200683 if (ret < 0)
684 return ret;
685
Shahar Levi48a61472011-03-06 16:32:08 +0200686 /* Chip-specific initializations */
687 ret = wl1271_chip_specific_init(wl);
688 if (ret < 0)
689 return ret;
690
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691 ret = wl1271_acx_init_mem_config(wl);
692 if (ret < 0)
693 return ret;
694
Eliad Peller7f0979882011-08-14 13:17:06 +0300695 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600696 if (ret < 0)
697 goto out_free_memmap;
698
Luciano Coelho12419cc2010-02-18 13:25:44 +0200699 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200700 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300701 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200702 goto out_free_memmap;
703
704 /* Configure for CAM power saving (ie. always active) */
705 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
706 if (ret < 0)
707 goto out_free_memmap;
708
709 /* configure PM */
710 ret = wl1271_acx_pm_config(wl);
711 if (ret < 0)
712 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713
714 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200715
716 out_free_memmap:
717 kfree(wl->target_mem_map);
718 wl->target_mem_map = NULL;
719
720 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300721}
722
Eliad Peller6e8cd332011-10-10 10:13:13 +0200723static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
724 struct wl12xx_vif *wlvif,
725 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200726{
Arik Nemtsovda032092011-08-25 12:43:15 +0300727 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200728
Arik Nemtsovb622d992011-02-23 00:22:31 +0200729 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300730 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200731
732 /*
733 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300734 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200735 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300736 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200737 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200738
Arik Nemtsovda032092011-08-25 12:43:15 +0300739 /*
740 * Start high-level PS if the STA is asleep with enough blocks in FW.
741 * Make an exception if this is the only connected station. In this
742 * case FW-memory congestion is not a problem.
743 */
744 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200745 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200746}
747
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300748static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200749 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300750 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200751{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200752 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200753 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300754 u8 hlid, cnt;
755
756 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200757
758 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
759 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
760 wl1271_debug(DEBUG_PSM,
761 "link ps prev 0x%x cur 0x%x changed 0x%x",
762 wl->ap_fw_ps_map, cur_fw_ps_map,
763 wl->ap_fw_ps_map ^ cur_fw_ps_map);
764
765 wl->ap_fw_ps_map = cur_fw_ps_map;
766 }
767
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200768 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
769 lnk = &wl->links[hlid];
770 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200771
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200772 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
773 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200774
Eliad Peller6e8cd332011-10-10 10:13:13 +0200775 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
776 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200777 }
778}
779
Eliad Peller4d56ad92011-08-14 13:17:05 +0300780static void wl12xx_fw_status(struct wl1271 *wl,
781 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300782{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200783 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200784 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200785 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300786 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300787 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300788
Eliad Peller4d56ad92011-08-14 13:17:05 +0300789 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200790
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300791 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
792 "drv_rx_counter = %d, tx_results_counter = %d)",
793 status->intr,
794 status->fw_rx_counter,
795 status->drv_rx_counter,
796 status->tx_results_counter);
797
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300798 for (i = 0; i < NUM_TX_QUEUES; i++) {
799 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300800 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300801 (status->tx_released_pkts[i] -
802 wl->tx_pkts_freed[i]) & 0xff;
803
804 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
805 }
806
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300807 /* prevent wrap-around in total blocks counter */
808 if (likely(wl->tx_blocks_freed <=
809 le32_to_cpu(status->total_released_blks)))
810 freed_blocks = le32_to_cpu(status->total_released_blks) -
811 wl->tx_blocks_freed;
812 else
813 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
814 le32_to_cpu(status->total_released_blks);
815
Eliad Peller4d56ad92011-08-14 13:17:05 +0300816 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200817
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300818 wl->tx_allocated_blocks -= freed_blocks;
819
Eliad Peller4d56ad92011-08-14 13:17:05 +0300820 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200821
Eliad Peller4d56ad92011-08-14 13:17:05 +0300822 /*
823 * The FW might change the total number of TX memblocks before
824 * we get a notification about blocks being released. Thus, the
825 * available blocks calculation might yield a temporary result
826 * which is lower than the actual available blocks. Keeping in
827 * mind that only blocks that were allocated can be moved from
828 * TX to RX, tx_blocks_available should never decrease here.
829 */
830 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
831 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300832
Ido Yariva5225502010-10-12 14:49:10 +0200833 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200834 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200835 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300836
Eliad Peller4d56ad92011-08-14 13:17:05 +0300837 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200838 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200839 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200840 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300841
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300842 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200843 getnstimeofday(&ts);
844 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
845 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846}
847
Ido Yariva6208652011-03-01 15:14:41 +0200848static void wl1271_flush_deferred_work(struct wl1271 *wl)
849{
850 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200851
Ido Yariva6208652011-03-01 15:14:41 +0200852 /* Pass all received frames to the network stack */
853 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
854 ieee80211_rx_ni(wl->hw, skb);
855
856 /* Return sent skbs to the network stack */
857 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300858 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200859}
860
861static void wl1271_netstack_work(struct work_struct *work)
862{
863 struct wl1271 *wl =
864 container_of(work, struct wl1271, netstack_work);
865
866 do {
867 wl1271_flush_deferred_work(wl);
868 } while (skb_queue_len(&wl->deferred_rx_queue));
869}
870
871#define WL1271_IRQ_MAX_LOOPS 256
872
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300873static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300874{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300875 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300876 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200877 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200878 struct wl1271 *wl = (struct wl1271 *)cookie;
879 bool done = false;
880 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200881 unsigned long flags;
882
883 /* TX might be handled here, avoid redundant work */
884 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
885 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300886
Ido Yariv341b7cd2011-03-31 10:07:01 +0200887 /*
888 * In case edge triggered interrupt must be used, we cannot iterate
889 * more than once without introducing race conditions with the hardirq.
890 */
891 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
892 loopcount = 1;
893
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300894 mutex_lock(&wl->mutex);
895
896 wl1271_debug(DEBUG_IRQ, "IRQ work");
897
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200898 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899 goto out;
900
Ido Yariva6208652011-03-01 15:14:41 +0200901 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902 if (ret < 0)
903 goto out;
904
Ido Yariva6208652011-03-01 15:14:41 +0200905 while (!done && loopcount--) {
906 /*
907 * In order to avoid a race with the hardirq, clear the flag
908 * before acknowledging the chip. Since the mutex is held,
909 * wl1271_ps_elp_wakeup cannot be called concurrently.
910 */
911 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
912 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200913
Eliad Peller4d56ad92011-08-14 13:17:05 +0300914 wl12xx_fw_status(wl, wl->fw_status);
915 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200916 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200917 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200918 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200919 continue;
920 }
921
Eliad Pellerccc83b02010-10-27 14:09:57 +0200922 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
923 wl1271_error("watchdog interrupt received! "
924 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300925 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200926
927 /* restarting the chip. ignore any other interrupt. */
928 goto out;
929 }
930
Ido Yariva6208652011-03-01 15:14:41 +0200931 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200932 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
933
Eliad Peller4d56ad92011-08-14 13:17:05 +0300934 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200935
Ido Yariva5225502010-10-12 14:49:10 +0200936 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200937 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200938 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300939 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200940 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200941 /*
942 * In order to avoid starvation of the TX path,
943 * call the work function directly.
944 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200945 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200946 } else {
947 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200948 }
949
Ido Yariv8aad2462011-03-01 15:14:38 +0200950 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300951 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200952 (wl->tx_results_count & 0xff))
953 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200954
955 /* Make sure the deferred queues don't get too long */
956 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
957 skb_queue_len(&wl->deferred_rx_queue);
958 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
959 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200960 }
961
962 if (intr & WL1271_ACX_INTR_EVENT_A) {
963 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
964 wl1271_event_handle(wl, 0);
965 }
966
967 if (intr & WL1271_ACX_INTR_EVENT_B) {
968 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
969 wl1271_event_handle(wl, 1);
970 }
971
972 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
973 wl1271_debug(DEBUG_IRQ,
974 "WL1271_ACX_INTR_INIT_COMPLETE");
975
976 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
977 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300978 }
979
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300980 wl1271_ps_elp_sleep(wl);
981
982out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200983 spin_lock_irqsave(&wl->wl_lock, flags);
984 /* In case TX was not handled here, queue TX work */
985 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
986 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300987 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200988 ieee80211_queue_work(wl->hw, &wl->tx_work);
989 spin_unlock_irqrestore(&wl->wl_lock, flags);
990
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200992
993 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300994}
995
Eliad Peller3fcdab72012-02-06 12:47:54 +0200996static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300997{
998 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200999 const char *fw_name;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001000 enum wl12xx_fw_type fw_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001001 int ret;
1002
Eliad Peller3fcdab72012-02-06 12:47:54 +02001003 if (plt) {
1004 fw_type = WL12XX_FW_TYPE_PLT;
1005 if (wl->chip.id == CHIP_ID_1283_PG20)
1006 fw_name = WL128X_PLT_FW_NAME;
1007 else
1008 fw_name = WL127X_PLT_FW_NAME;
1009 } else {
1010 fw_type = WL12XX_FW_TYPE_NORMAL;
1011 if (wl->chip.id == CHIP_ID_1283_PG20)
1012 fw_name = WL128X_FW_NAME;
1013 else
1014 fw_name = WL127X_FW_NAME;
1015 }
1016
1017 if (wl->fw_type == fw_type)
1018 return 0;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001019
1020 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1021
Felipe Balbia390e852011-10-06 10:07:44 +03001022 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001023
1024 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001025 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026 return ret;
1027 }
1028
1029 if (fw->size % 4) {
1030 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1031 fw->size);
1032 ret = -EILSEQ;
1033 goto out;
1034 }
1035
Arik Nemtsov166d5042010-10-16 21:44:57 +02001036 vfree(wl->fw);
Eliad Peller3fcdab72012-02-06 12:47:54 +02001037 wl->fw_type = WL12XX_FW_TYPE_NONE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001038 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001039 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040
1041 if (!wl->fw) {
1042 wl1271_error("could not allocate memory for the firmware");
1043 ret = -ENOMEM;
1044 goto out;
1045 }
1046
1047 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048 ret = 0;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001049 wl->fw_type = fw_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050out:
1051 release_firmware(fw);
1052
1053 return ret;
1054}
1055
1056static int wl1271_fetch_nvs(struct wl1271 *wl)
1057{
1058 const struct firmware *fw;
1059 int ret;
1060
Felipe Balbia390e852011-10-06 10:07:44 +03001061 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062
1063 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001064 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
1065 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066 return ret;
1067 }
1068
Shahar Levibc765bf2011-03-06 16:32:10 +02001069 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001070
1071 if (!wl->nvs) {
1072 wl1271_error("could not allocate memory for the nvs file");
1073 ret = -ENOMEM;
1074 goto out;
1075 }
1076
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001077 wl->nvs_len = fw->size;
1078
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001079out:
1080 release_firmware(fw);
1081
1082 return ret;
1083}
1084
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001085void wl12xx_queue_recovery_work(struct wl1271 *wl)
1086{
1087 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1088 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1089}
1090
Ido Yariv95dac04f2011-06-06 14:57:06 +03001091size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1092{
1093 size_t len = 0;
1094
1095 /* The FW log is a length-value list, find where the log end */
1096 while (len < maxlen) {
1097 if (memblock[len] == 0)
1098 break;
1099 if (len + memblock[len] + 1 > maxlen)
1100 break;
1101 len += memblock[len] + 1;
1102 }
1103
1104 /* Make sure we have enough room */
1105 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1106
1107 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1108 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1109 wl->fwlog_size += len;
1110
1111 return len;
1112}
1113
1114static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1115{
1116 u32 addr;
1117 u32 first_addr;
1118 u8 *block;
1119
1120 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1121 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1122 (wl->conf.fwlog.mem_blocks == 0))
1123 return;
1124
1125 wl1271_info("Reading FW panic log");
1126
1127 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1128 if (!block)
1129 return;
1130
1131 /*
1132 * Make sure the chip is awake and the logger isn't active.
1133 * This might fail if the firmware hanged.
1134 */
1135 if (!wl1271_ps_elp_wakeup(wl))
1136 wl12xx_cmd_stop_fwlog(wl);
1137
1138 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001139 wl12xx_fw_status(wl, wl->fw_status);
1140 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001141 if (!first_addr)
1142 goto out;
1143
1144 /* Traverse the memory blocks linked list */
1145 addr = first_addr;
1146 do {
1147 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1148 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1149 false);
1150
1151 /*
1152 * Memory blocks are linked to one another. The first 4 bytes
1153 * of each memory block hold the hardware address of the next
1154 * one. The last memory block points to the first one.
1155 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001156 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001157 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1158 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1159 break;
1160 } while (addr && (addr != first_addr));
1161
1162 wake_up_interruptible(&wl->fwlog_waitq);
1163
1164out:
1165 kfree(block);
1166}
1167
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001168static void wl1271_recovery_work(struct work_struct *work)
1169{
1170 struct wl1271 *wl =
1171 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001172 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001173 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001174
1175 mutex_lock(&wl->mutex);
1176
Eliad Peller3fcdab72012-02-06 12:47:54 +02001177 if (wl->state != WL1271_STATE_ON || wl->plt)
Eliad Pellerf0277432011-10-10 10:13:14 +02001178 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001179
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001180 /* Avoid a recursive recovery */
1181 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1182
Ido Yariv95dac04f2011-06-06 14:57:06 +03001183 wl12xx_read_fwlog_panic(wl);
1184
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001185 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1186 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001187
Eliad Peller2a5bff02011-08-25 18:10:59 +03001188 BUG_ON(bug_on_recovery);
1189
Oz Krakowskib992c682011-06-26 10:36:02 +03001190 /*
1191 * Advance security sequence number to overcome potential progress
1192 * in the firmware during recovery. This doens't hurt if the network is
1193 * not encrypted.
1194 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001195 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001196 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001197 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001198 wlvif->tx_security_seq +=
1199 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1200 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001201
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001202 /* Prevent spurious TX during FW restart */
1203 ieee80211_stop_queues(wl->hw);
1204
Luciano Coelho33c2c062011-05-10 14:46:02 +03001205 if (wl->sched_scanning) {
1206 ieee80211_sched_scan_stopped(wl->hw);
1207 wl->sched_scanning = false;
1208 }
1209
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001210 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001211 while (!list_empty(&wl->wlvif_list)) {
1212 wlvif = list_first_entry(&wl->wlvif_list,
1213 struct wl12xx_vif, list);
1214 vif = wl12xx_wlvif_to_vif(wlvif);
1215 __wl1271_op_remove_interface(wl, vif, false);
1216 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001217 mutex_unlock(&wl->mutex);
1218 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001219
1220 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1221
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001222 ieee80211_restart_hw(wl->hw);
1223
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001224 /*
1225 * Its safe to enable TX now - the queues are stopped after a request
1226 * to restart the HW.
1227 */
1228 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001229 return;
1230out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001231 mutex_unlock(&wl->mutex);
1232}
1233
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001234static void wl1271_fw_wakeup(struct wl1271 *wl)
1235{
1236 u32 elp_reg;
1237
1238 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001239 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001240}
1241
1242static int wl1271_setup(struct wl1271 *wl)
1243{
1244 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1245 if (!wl->fw_status)
1246 return -ENOMEM;
1247
1248 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1249 if (!wl->tx_res_if) {
1250 kfree(wl->fw_status);
1251 return -ENOMEM;
1252 }
1253
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254 return 0;
1255}
1256
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001257static int wl12xx_set_power_on(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001258{
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001259 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001260
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001261 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001262 ret = wl1271_power_on(wl);
1263 if (ret < 0)
1264 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001265 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001266 wl1271_io_reset(wl);
1267 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001268
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001269 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001270
1271 /* ELP module wake up */
1272 wl1271_fw_wakeup(wl);
1273
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001274out:
1275 return ret;
1276}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001277
Eliad Peller3fcdab72012-02-06 12:47:54 +02001278static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001279{
1280 int ret = 0;
1281
1282 ret = wl12xx_set_power_on(wl);
1283 if (ret < 0)
1284 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001286 /*
1287 * For wl127x based devices we could use the default block
1288 * size (512 bytes), but due to a bug in the sdio driver, we
1289 * need to set it explicitly after the chip is powered on. To
1290 * simplify the code and since the performance impact is
1291 * negligible, we use the same block size for all different
1292 * chip types.
1293 */
1294 if (!wl1271_set_block_size(wl))
1295 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296
1297 switch (wl->chip.id) {
1298 case CHIP_ID_1271_PG10:
1299 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1300 wl->chip.id);
1301
1302 ret = wl1271_setup(wl);
1303 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001304 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001305 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001307
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001308 case CHIP_ID_1271_PG20:
1309 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1310 wl->chip.id);
1311
1312 ret = wl1271_setup(wl);
1313 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001314 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001315 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001316 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001317
Shahar Levi0830cee2011-03-06 16:32:20 +02001318 case CHIP_ID_1283_PG20:
1319 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1320 wl->chip.id);
1321
1322 ret = wl1271_setup(wl);
1323 if (ret < 0)
1324 goto out;
1325 break;
1326 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001328 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001330 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331 }
1332
Eliad Peller3fcdab72012-02-06 12:47:54 +02001333 ret = wl12xx_fetch_firmware(wl, plt);
1334 if (ret < 0)
1335 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001336
1337 /* No NVS from netlink, try to get it from the filesystem */
1338 if (wl->nvs == NULL) {
1339 ret = wl1271_fetch_nvs(wl);
1340 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001341 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001342 }
1343
1344out:
1345 return ret;
1346}
1347
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001348int wl1271_plt_start(struct wl1271 *wl)
1349{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001350 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001351 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001352 int ret;
1353
1354 mutex_lock(&wl->mutex);
1355
1356 wl1271_notice("power up");
1357
1358 if (wl->state != WL1271_STATE_OFF) {
1359 wl1271_error("cannot go into PLT state because not "
1360 "in off state: %d", wl->state);
1361 ret = -EBUSY;
1362 goto out;
1363 }
1364
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001365 while (retries) {
1366 retries--;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001367 ret = wl12xx_chip_wakeup(wl, true);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001368 if (ret < 0)
1369 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001371 ret = wl1271_boot(wl);
1372 if (ret < 0)
1373 goto power_off;
1374
1375 ret = wl1271_plt_init(wl);
1376 if (ret < 0)
1377 goto irq_disable;
1378
Eliad Peller3fcdab72012-02-06 12:47:54 +02001379 wl->plt = true;
1380 wl->state = WL1271_STATE_ON;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001381 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001382 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001383
Gery Kahn6f07b722011-07-18 14:21:49 +03001384 /* update hw/fw version info in wiphy struct */
1385 wiphy->hw_version = wl->chip.id;
1386 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1387 sizeof(wiphy->fw_version));
1388
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001389 goto out;
1390
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001391irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001392 mutex_unlock(&wl->mutex);
1393 /* Unlocking the mutex in the middle of handling is
1394 inherently unsafe. In this case we deem it safe to do,
1395 because we need to let any possibly pending IRQ out of
1396 the system (and while we are WL1271_STATE_OFF the IRQ
1397 work function will not do anything.) Also, any other
1398 possible concurrent operations will fail due to the
1399 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001400 wl1271_disable_interrupts(wl);
1401 wl1271_flush_deferred_work(wl);
1402 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001403 mutex_lock(&wl->mutex);
1404power_off:
1405 wl1271_power_off(wl);
1406 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001408 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1409 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001410out:
1411 mutex_unlock(&wl->mutex);
1412
1413 return ret;
1414}
1415
Ido Yarivf3df1332012-01-11 09:42:39 +02001416int wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001417{
1418 int ret = 0;
1419
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420 wl1271_notice("power down");
1421
Ido Yariv46b0cc92012-01-11 09:42:41 +02001422 /*
1423 * Interrupts must be disabled before setting the state to OFF.
1424 * Otherwise, the interrupt handler might be called and exit without
1425 * reading the interrupt status.
1426 */
1427 wl1271_disable_interrupts(wl);
Ido Yarivf3df1332012-01-11 09:42:39 +02001428 mutex_lock(&wl->mutex);
Eliad Peller3fcdab72012-02-06 12:47:54 +02001429 if (!wl->plt) {
Ido Yarivf3df1332012-01-11 09:42:39 +02001430 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001431
1432 /*
1433 * This will not necessarily enable interrupts as interrupts
1434 * may have been disabled when op_stop was called. It will,
1435 * however, balance the above call to disable_interrupts().
1436 */
1437 wl1271_enable_interrupts(wl);
1438
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001439 wl1271_error("cannot power down because not in PLT "
1440 "state: %d", wl->state);
1441 ret = -EBUSY;
1442 goto out;
1443 }
1444
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001445 mutex_unlock(&wl->mutex);
Ido Yarivf3df1332012-01-11 09:42:39 +02001446
Ido Yariva6208652011-03-01 15:14:41 +02001447 wl1271_flush_deferred_work(wl);
1448 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001449 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001450 cancel_delayed_work_sync(&wl->elp_work);
Ido Yariva4549692012-01-11 09:42:40 +02001451
1452 mutex_lock(&wl->mutex);
1453 wl1271_power_off(wl);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001454 wl->flags = 0;
1455 wl->state = WL1271_STATE_OFF;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001456 wl->plt = false;
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001457 wl->rx_counter = 0;
Ido Yariva4549692012-01-11 09:42:40 +02001458 mutex_unlock(&wl->mutex);
1459
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001460out:
1461 return ret;
1462}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001463
Johannes Berg7bb45682011-02-24 14:42:06 +01001464static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465{
1466 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001467 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1468 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001469 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001470 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001471 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001472 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001473
Eliad Peller0f168012011-10-11 13:52:25 +02001474 if (vif)
1475 wlvif = wl12xx_vif_to_data(vif);
1476
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001477 mapping = skb_get_queue_mapping(skb);
1478 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001479
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001480 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001481
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001482 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001483
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001484 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001485 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001486 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001487 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001488 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001489 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001490 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001491
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001492 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1493 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1494
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001495 wl->tx_queue_count[q]++;
1496
1497 /*
1498 * The workqueue is slow to process the tx_queue and we need stop
1499 * the queue here, otherwise the queue will get too long.
1500 */
1501 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1502 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1503 ieee80211_stop_queue(wl->hw, mapping);
1504 set_bit(q, &wl->stopped_queues_map);
1505 }
1506
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001507 /*
1508 * The chip specific setup must run before the first TX packet -
1509 * before that, the tx_work will not be initialized!
1510 */
1511
Ido Yarivb07d4032011-03-01 15:14:43 +02001512 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1513 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001514 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001515
Arik Nemtsov04216da2011-08-14 13:17:38 +03001516out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001517 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001518}
1519
Shahar Leviae47c452011-03-06 16:32:14 +02001520int wl1271_tx_dummy_packet(struct wl1271 *wl)
1521{
Ido Yariv990f5de2011-03-31 10:06:59 +02001522 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001523 int q;
1524
1525 /* no need to queue a new dummy packet if one is already pending */
1526 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1527 return 0;
1528
1529 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001530
Ido Yariv990f5de2011-03-31 10:06:59 +02001531 spin_lock_irqsave(&wl->wl_lock, flags);
1532 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001533 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001534 spin_unlock_irqrestore(&wl->wl_lock, flags);
1535
1536 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1537 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001538 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001539
1540 /*
1541 * If the FW TX is busy, TX work will be scheduled by the threaded
1542 * interrupt handler function
1543 */
1544 return 0;
1545}
1546
1547/*
1548 * The size of the dummy packet should be at least 1400 bytes. However, in
1549 * order to minimize the number of bus transactions, aligning it to 512 bytes
1550 * boundaries could be beneficial, performance wise
1551 */
1552#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1553
Luciano Coelhocf27d862011-04-01 21:08:23 +03001554static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001555{
1556 struct sk_buff *skb;
1557 struct ieee80211_hdr_3addr *hdr;
1558 unsigned int dummy_packet_size;
1559
1560 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1561 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1562
1563 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001564 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001565 wl1271_warning("Failed to allocate a dummy packet skb");
1566 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001567 }
1568
1569 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1570
1571 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1572 memset(hdr, 0, sizeof(*hdr));
1573 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001574 IEEE80211_STYPE_NULLFUNC |
1575 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001576
Ido Yariv990f5de2011-03-31 10:06:59 +02001577 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001578
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001579 /* Dummy packets require the TID to be management */
1580 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001581
1582 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001583 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001584 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001585
Ido Yariv990f5de2011-03-31 10:06:59 +02001586 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001587}
1588
Ido Yariv990f5de2011-03-31 10:06:59 +02001589
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001590static struct notifier_block wl1271_dev_notifier = {
1591 .notifier_call = wl1271_dev_notify,
1592};
1593
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001594#ifdef CONFIG_PM
Eyal Shapiradae728f2012-02-02 12:03:39 +02001595static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1596 struct wl12xx_vif *wlvif)
1597{
1598 int ret = 0;
1599
1600 mutex_lock(&wl->mutex);
1601
1602 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
1603 goto out_unlock;
1604
1605 ret = wl1271_ps_elp_wakeup(wl);
1606 if (ret < 0)
1607 goto out_unlock;
1608
1609 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1610 wl->conf.conn.suspend_wake_up_event,
1611 wl->conf.conn.suspend_listen_interval);
1612
1613 if (ret < 0)
1614 wl1271_error("suspend: set wake up conditions failed: %d", ret);
1615
1616
1617 wl1271_ps_elp_sleep(wl);
1618
1619out_unlock:
1620 mutex_unlock(&wl->mutex);
1621 return ret;
1622
1623}
Eliad Peller94390642011-05-13 11:57:13 +03001624
Eliad Peller0603d892011-10-05 11:55:51 +02001625static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1626 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001627{
Eliad Pellere85d1622011-06-27 13:06:43 +03001628 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001629
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001630 mutex_lock(&wl->mutex);
1631
Eliad Peller53d40d02011-10-10 10:13:02 +02001632 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001633 goto out_unlock;
1634
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001635 ret = wl1271_ps_elp_wakeup(wl);
1636 if (ret < 0)
1637 goto out_unlock;
1638
Eliad Peller0603d892011-10-05 11:55:51 +02001639 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001640
1641 wl1271_ps_elp_sleep(wl);
1642out_unlock:
1643 mutex_unlock(&wl->mutex);
1644 return ret;
1645
1646}
1647
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001648static int wl1271_configure_suspend(struct wl1271 *wl,
1649 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001650{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001651 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
1652 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001653 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001654 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001655 return 0;
1656}
1657
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001658static void wl1271_configure_resume(struct wl1271 *wl,
1659 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001660{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001661 int ret = 0;
Eliad Peller536129c2011-10-05 11:55:45 +02001662 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001663 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001664
Eyal Shapiradae728f2012-02-02 12:03:39 +02001665 if ((!is_ap) && (!is_sta))
Eliad Peller94390642011-05-13 11:57:13 +03001666 return;
1667
1668 mutex_lock(&wl->mutex);
1669 ret = wl1271_ps_elp_wakeup(wl);
1670 if (ret < 0)
1671 goto out;
1672
Eyal Shapiradae728f2012-02-02 12:03:39 +02001673 if (is_sta) {
1674 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1675 wl->conf.conn.wake_up_event,
1676 wl->conf.conn.listen_interval);
1677
1678 if (ret < 0)
1679 wl1271_error("resume: wake up conditions failed: %d",
1680 ret);
1681
1682 } else if (is_ap) {
1683 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
1684 }
Eliad Peller94390642011-05-13 11:57:13 +03001685
1686 wl1271_ps_elp_sleep(wl);
1687out:
1688 mutex_unlock(&wl->mutex);
1689}
1690
Eliad Peller402e48612011-05-13 11:57:09 +03001691static int wl1271_op_suspend(struct ieee80211_hw *hw,
1692 struct cfg80211_wowlan *wow)
1693{
1694 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001695 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001696 int ret;
1697
Eliad Peller402e48612011-05-13 11:57:09 +03001698 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001699 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001700
Eliad Peller4a859df2011-06-06 12:21:52 +03001701 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001702 wl12xx_for_each_wlvif(wl, wlvif) {
1703 ret = wl1271_configure_suspend(wl, wlvif);
1704 if (ret < 0) {
1705 wl1271_warning("couldn't prepare device to suspend");
1706 return ret;
1707 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001708 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001709 /* flush any remaining work */
1710 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001711
1712 /*
1713 * disable and re-enable interrupts in order to flush
1714 * the threaded_irq
1715 */
1716 wl1271_disable_interrupts(wl);
1717
1718 /*
1719 * set suspended flag to avoid triggering a new threaded_irq
1720 * work. no need for spinlock as interrupts are disabled.
1721 */
1722 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1723
1724 wl1271_enable_interrupts(wl);
1725 flush_work(&wl->tx_work);
Eliad Peller4a859df2011-06-06 12:21:52 +03001726 flush_delayed_work(&wl->elp_work);
1727
Eliad Peller402e48612011-05-13 11:57:09 +03001728 return 0;
1729}
1730
1731static int wl1271_op_resume(struct ieee80211_hw *hw)
1732{
1733 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001734 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001735 unsigned long flags;
1736 bool run_irq_work = false;
1737
Eliad Peller402e48612011-05-13 11:57:09 +03001738 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1739 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001740 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001741
1742 /*
1743 * re-enable irq_work enqueuing, and call irq_work directly if
1744 * there is a pending work.
1745 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001746 spin_lock_irqsave(&wl->wl_lock, flags);
1747 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1748 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1749 run_irq_work = true;
1750 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001751
Eliad Peller4a859df2011-06-06 12:21:52 +03001752 if (run_irq_work) {
1753 wl1271_debug(DEBUG_MAC80211,
1754 "run postponed irq_work directly");
1755 wl1271_irq(0, wl);
1756 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001757 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001758 wl12xx_for_each_wlvif(wl, wlvif) {
1759 wl1271_configure_resume(wl, wlvif);
1760 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001761 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001762
Eliad Peller402e48612011-05-13 11:57:09 +03001763 return 0;
1764}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001765#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001766
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001767static int wl1271_op_start(struct ieee80211_hw *hw)
1768{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001769 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1770
1771 /*
1772 * We have to delay the booting of the hardware because
1773 * we need to know the local MAC address before downloading and
1774 * initializing the firmware. The MAC address cannot be changed
1775 * after boot, and without the proper MAC address, the firmware
1776 * will not function properly.
1777 *
1778 * The MAC address is first known when the corresponding interface
1779 * is added. That is where we will initialize the hardware.
1780 */
1781
Eyal Shapirad18da7f2012-01-31 11:57:25 +02001782 return 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001783}
1784
1785static void wl1271_op_stop(struct ieee80211_hw *hw)
1786{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001787 struct wl1271 *wl = hw->priv;
1788 int i;
1789
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001790 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001791
Ido Yariv46b0cc92012-01-11 09:42:41 +02001792 /*
1793 * Interrupts must be disabled before setting the state to OFF.
1794 * Otherwise, the interrupt handler might be called and exit without
1795 * reading the interrupt status.
1796 */
1797 wl1271_disable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001798 mutex_lock(&wl->mutex);
1799 if (wl->state == WL1271_STATE_OFF) {
1800 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001801
1802 /*
1803 * This will not necessarily enable interrupts as interrupts
1804 * may have been disabled when op_stop was called. It will,
1805 * however, balance the above call to disable_interrupts().
1806 */
1807 wl1271_enable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001808 return;
1809 }
Ido Yariv46b0cc92012-01-11 09:42:41 +02001810
Eliad Pellerbaf62772011-10-10 10:12:52 +02001811 /*
1812 * this must be before the cancel_work calls below, so that the work
1813 * functions don't perform further work.
1814 */
1815 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001816 mutex_unlock(&wl->mutex);
1817
1818 mutex_lock(&wl_list_mutex);
1819 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001820 mutex_unlock(&wl_list_mutex);
1821
Eliad Pellerbaf62772011-10-10 10:12:52 +02001822 wl1271_flush_deferred_work(wl);
1823 cancel_delayed_work_sync(&wl->scan_complete_work);
1824 cancel_work_sync(&wl->netstack_work);
1825 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001826 cancel_delayed_work_sync(&wl->elp_work);
1827
1828 /* let's notify MAC80211 about the remaining pending TX frames */
1829 wl12xx_tx_reset(wl, true);
1830 mutex_lock(&wl->mutex);
1831
1832 wl1271_power_off(wl);
1833
1834 wl->band = IEEE80211_BAND_2GHZ;
1835
1836 wl->rx_counter = 0;
1837 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1838 wl->tx_blocks_available = 0;
1839 wl->tx_allocated_blocks = 0;
1840 wl->tx_results_count = 0;
1841 wl->tx_packets_count = 0;
1842 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001843 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1844 wl->ap_fw_ps_map = 0;
1845 wl->ap_ps_map = 0;
1846 wl->sched_scanning = false;
1847 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1848 memset(wl->links_map, 0, sizeof(wl->links_map));
1849 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1850 wl->active_sta_count = 0;
1851
1852 /* The system link is always allocated */
1853 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1854
1855 /*
1856 * this is performed after the cancel_work calls and the associated
1857 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1858 * get executed before all these vars have been reset.
1859 */
1860 wl->flags = 0;
1861
1862 wl->tx_blocks_freed = 0;
1863
1864 for (i = 0; i < NUM_TX_QUEUES; i++) {
1865 wl->tx_pkts_freed[i] = 0;
1866 wl->tx_allocated_pkts[i] = 0;
1867 }
1868
1869 wl1271_debugfs_reset(wl);
1870
1871 kfree(wl->fw_status);
1872 wl->fw_status = NULL;
1873 kfree(wl->tx_res_if);
1874 wl->tx_res_if = NULL;
1875 kfree(wl->target_mem_map);
1876 wl->target_mem_map = NULL;
1877
1878 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001879}
1880
Eliad Pellere5a359f2011-10-10 10:13:15 +02001881static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1882{
1883 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1884 WL12XX_MAX_RATE_POLICIES);
1885 if (policy >= WL12XX_MAX_RATE_POLICIES)
1886 return -EBUSY;
1887
1888 __set_bit(policy, wl->rate_policies_map);
1889 *idx = policy;
1890 return 0;
1891}
1892
1893static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1894{
1895 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1896 return;
1897
1898 __clear_bit(*idx, wl->rate_policies_map);
1899 *idx = WL12XX_MAX_RATE_POLICIES;
1900}
1901
Eliad Peller536129c2011-10-05 11:55:45 +02001902static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001903{
Eliad Peller536129c2011-10-05 11:55:45 +02001904 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001905 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001906 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001907 return WL1271_ROLE_P2P_GO;
1908 else
1909 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001910
1911 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001912 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001913 return WL1271_ROLE_P2P_CL;
1914 else
1915 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001916
Eliad Peller227e81e2011-08-14 13:17:26 +03001917 case BSS_TYPE_IBSS:
1918 return WL1271_ROLE_IBSS;
1919
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001920 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001921 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001922 }
1923 return WL12XX_INVALID_ROLE_TYPE;
1924}
1925
Eliad Peller83587502011-10-10 10:12:53 +02001926static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001927{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001928 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001929 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001930
Eliad Peller48e93e42011-10-10 10:12:58 +02001931 /* clear everything but the persistent data */
1932 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001933
1934 switch (ieee80211_vif_type_p2p(vif)) {
1935 case NL80211_IFTYPE_P2P_CLIENT:
1936 wlvif->p2p = 1;
1937 /* fall-through */
1938 case NL80211_IFTYPE_STATION:
1939 wlvif->bss_type = BSS_TYPE_STA_BSS;
1940 break;
1941 case NL80211_IFTYPE_ADHOC:
1942 wlvif->bss_type = BSS_TYPE_IBSS;
1943 break;
1944 case NL80211_IFTYPE_P2P_GO:
1945 wlvif->p2p = 1;
1946 /* fall-through */
1947 case NL80211_IFTYPE_AP:
1948 wlvif->bss_type = BSS_TYPE_AP_BSS;
1949 break;
1950 default:
1951 wlvif->bss_type = MAX_BSS_TYPE;
1952 return -EOPNOTSUPP;
1953 }
1954
Eliad Peller0603d892011-10-05 11:55:51 +02001955 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001956 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001957 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001958
Eliad Pellere936bbe2011-10-05 11:55:56 +02001959 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1960 wlvif->bss_type == BSS_TYPE_IBSS) {
1961 /* init sta/ibss data */
1962 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001963 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1964 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1965 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001966 } else {
1967 /* init ap data */
1968 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1969 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001970 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1971 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1972 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1973 wl12xx_allocate_rate_policy(wl,
1974 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001975 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001976
Eliad Peller83587502011-10-10 10:12:53 +02001977 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1978 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001979 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001980 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001981 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001982 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1983
Eliad Peller1b92f152011-10-10 10:13:09 +02001984 /*
1985 * mac80211 configures some values globally, while we treat them
1986 * per-interface. thus, on init, we have to copy them from wl
1987 */
1988 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001989 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001990 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02001991
Eliad Peller9eb599e2011-10-10 10:12:59 +02001992 INIT_WORK(&wlvif->rx_streaming_enable_work,
1993 wl1271_rx_streaming_enable_work);
1994 INIT_WORK(&wlvif->rx_streaming_disable_work,
1995 wl1271_rx_streaming_disable_work);
Eliad Peller87627212011-10-10 10:12:54 +02001996 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001997
Eliad Peller9eb599e2011-10-10 10:12:59 +02001998 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1999 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002000 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002001}
2002
Eliad Peller1d095472011-10-10 10:12:49 +02002003static bool wl12xx_init_fw(struct wl1271 *wl)
2004{
2005 int retries = WL1271_BOOT_RETRIES;
2006 bool booted = false;
2007 struct wiphy *wiphy = wl->hw->wiphy;
2008 int ret;
2009
2010 while (retries) {
2011 retries--;
Eliad Peller3fcdab72012-02-06 12:47:54 +02002012 ret = wl12xx_chip_wakeup(wl, false);
Eliad Peller1d095472011-10-10 10:12:49 +02002013 if (ret < 0)
2014 goto power_off;
2015
2016 ret = wl1271_boot(wl);
2017 if (ret < 0)
2018 goto power_off;
2019
2020 ret = wl1271_hw_init(wl);
2021 if (ret < 0)
2022 goto irq_disable;
2023
2024 booted = true;
2025 break;
2026
2027irq_disable:
2028 mutex_unlock(&wl->mutex);
2029 /* Unlocking the mutex in the middle of handling is
2030 inherently unsafe. In this case we deem it safe to do,
2031 because we need to let any possibly pending IRQ out of
2032 the system (and while we are WL1271_STATE_OFF the IRQ
2033 work function will not do anything.) Also, any other
2034 possible concurrent operations will fail due to the
2035 current state, hence the wl1271 struct should be safe. */
2036 wl1271_disable_interrupts(wl);
2037 wl1271_flush_deferred_work(wl);
2038 cancel_work_sync(&wl->netstack_work);
2039 mutex_lock(&wl->mutex);
2040power_off:
2041 wl1271_power_off(wl);
2042 }
2043
2044 if (!booted) {
2045 wl1271_error("firmware boot failed despite %d retries",
2046 WL1271_BOOT_RETRIES);
2047 goto out;
2048 }
2049
2050 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2051
2052 /* update hw/fw version info in wiphy struct */
2053 wiphy->hw_version = wl->chip.id;
2054 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2055 sizeof(wiphy->fw_version));
2056
2057 /*
2058 * Now we know if 11a is supported (info from the NVS), so disable
2059 * 11a channels if not supported
2060 */
2061 if (!wl->enable_11a)
2062 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2063
2064 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2065 wl->enable_11a ? "" : "not ");
2066
2067 wl->state = WL1271_STATE_ON;
2068out:
2069 return booted;
2070}
2071
Eliad Peller92e712d2011-12-18 20:25:43 +02002072static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2073{
2074 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2075}
2076
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002077static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2078 struct ieee80211_vif *vif)
2079{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002080 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002081 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002082 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002083 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002084 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002085
Johannes Bergea086352012-01-19 09:29:58 +01002086 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2087 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002088
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002089 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002090 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002091
2092 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002093 ret = wl1271_ps_elp_wakeup(wl);
2094 if (ret < 0)
2095 goto out_unlock;
2096
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002097 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002098 wl1271_debug(DEBUG_MAC80211,
2099 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002100 ret = -EBUSY;
2101 goto out;
2102 }
2103
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002104 /*
2105 * in some very corner case HW recovery scenarios its possible to
2106 * get here before __wl1271_op_remove_interface is complete, so
2107 * opt out if that is the case.
2108 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002109 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2110 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002111 ret = -EBUSY;
2112 goto out;
2113 }
2114
Eliad Peller3fcdab72012-02-06 12:47:54 +02002115
Eliad Peller83587502011-10-10 10:12:53 +02002116 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002117 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002118 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002119
Eliad Peller252efa42011-10-05 11:56:00 +02002120 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002121 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002122 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2123 ret = -EINVAL;
2124 goto out;
2125 }
Eliad Peller1d095472011-10-10 10:12:49 +02002126
Eliad Peller784f6942011-10-05 11:55:39 +02002127 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002128 * TODO: after the nvs issue will be solved, move this block
2129 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002130 */
Eliad Peller1d095472011-10-10 10:12:49 +02002131 if (wl->state == WL1271_STATE_OFF) {
2132 /*
2133 * we still need this in order to configure the fw
2134 * while uploading the nvs
2135 */
Luciano Coelho5e037e72011-12-23 09:32:17 +02002136 memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002137
Eliad Peller1d095472011-10-10 10:12:49 +02002138 booted = wl12xx_init_fw(wl);
2139 if (!booted) {
2140 ret = -EINVAL;
2141 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002142 }
Eliad Peller1d095472011-10-10 10:12:49 +02002143 }
Eliad Peller04e80792011-08-14 13:17:09 +03002144
Eliad Peller1d095472011-10-10 10:12:49 +02002145 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2146 wlvif->bss_type == BSS_TYPE_IBSS) {
2147 /*
2148 * The device role is a special role used for
2149 * rx and tx frames prior to association (as
2150 * the STA role can get packets only from
2151 * its associated bssid)
2152 */
Eliad Peller784f6942011-10-05 11:55:39 +02002153 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002154 WL1271_ROLE_DEVICE,
2155 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002156 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002157 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002158 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002159
Eliad Peller1d095472011-10-10 10:12:49 +02002160 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2161 role_type, &wlvif->role_id);
2162 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002163 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002164
2165 ret = wl1271_init_vif_specific(wl, vif);
2166 if (ret < 0)
2167 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002168
2169 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002170 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002171 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002172
2173 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2174 wl->ap_count++;
2175 else
2176 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002177out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002178 wl1271_ps_elp_sleep(wl);
2179out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002180 mutex_unlock(&wl->mutex);
2181
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002182 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002183 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002184 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002185 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002186
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002187 return ret;
2188}
2189
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002190static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002191 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002192 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002193{
Eliad Peller536129c2011-10-05 11:55:45 +02002194 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002195 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002196
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002197 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002198
Eliad Peller10c8cd02011-10-10 10:13:06 +02002199 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2200 return;
2201
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002202 wl->vif = NULL;
2203
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002204 /* because of hardware recovery, we may get here twice */
2205 if (wl->state != WL1271_STATE_ON)
2206 return;
2207
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002208 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002209
Eliad Pellerbaf62772011-10-10 10:12:52 +02002210 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2211 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002212 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002213 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002214 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002215 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002216 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002217 }
2218
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002219 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2220 /* disable active roles */
2221 ret = wl1271_ps_elp_wakeup(wl);
2222 if (ret < 0)
2223 goto deinit;
2224
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002225 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2226 wlvif->bss_type == BSS_TYPE_IBSS) {
2227 if (wl12xx_dev_role_started(wlvif))
2228 wl12xx_stop_dev(wl, wlvif);
2229
Eliad Peller7edebf52011-10-05 11:55:52 +02002230 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002231 if (ret < 0)
2232 goto deinit;
2233 }
2234
Eliad Peller0603d892011-10-05 11:55:51 +02002235 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002236 if (ret < 0)
2237 goto deinit;
2238
2239 wl1271_ps_elp_sleep(wl);
2240 }
2241deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002242 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002243 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002244
2245 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2246 wlvif->bss_type == BSS_TYPE_IBSS) {
2247 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2248 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2249 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2250 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2251 } else {
2252 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2253 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2254 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2255 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2256 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2257 wl12xx_free_rate_policy(wl,
2258 &wlvif->ap.ucast_rate_idx[i]);
2259 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002260
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002261 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002262 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002263 if (wl->last_wlvif == wlvif)
2264 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002265 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002266 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002267 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002268 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002269
Eliad Pellera4e41302011-10-11 11:49:15 +02002270 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2271 wl->ap_count--;
2272 else
2273 wl->sta_count--;
2274
Eliad Pellerbaf62772011-10-10 10:12:52 +02002275 mutex_unlock(&wl->mutex);
Eyal Shapirad6bf9ad2012-01-31 11:57:20 +02002276
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 Pellerf4df1bd2011-08-14 13:17:15 +03002280
Eliad Pellerbaf62772011-10-10 10:12:52 +02002281 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002282}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002283
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002284static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2285 struct ieee80211_vif *vif)
2286{
2287 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002288 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002289 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002290
2291 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002292
2293 if (wl->state == WL1271_STATE_OFF ||
2294 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2295 goto out;
2296
Juuso Oikarinen67353292010-11-18 15:19:02 +02002297 /*
2298 * wl->vif can be null here if someone shuts down the interface
2299 * just when hardware recovery has been started.
2300 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002301 wl12xx_for_each_wlvif(wl, iter) {
2302 if (iter != wlvif)
2303 continue;
2304
Eliad Peller536129c2011-10-05 11:55:45 +02002305 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002306 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002307 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002308 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002309out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002310 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002311 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002312}
2313
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002314static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2315 struct ieee80211_vif *vif,
2316 enum nl80211_iftype new_type, bool p2p)
2317{
2318 wl1271_op_remove_interface(hw, vif);
2319
2320 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2321 vif->p2p = p2p;
2322 return wl1271_op_add_interface(hw, vif);
2323}
2324
Eliad Peller87fbcb02011-10-05 11:55:41 +02002325static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2326 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002327{
2328 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002329 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002330
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002331 /*
2332 * One of the side effects of the JOIN command is that is clears
2333 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2334 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002335 * Currently the only valid scenario for JOIN during association
2336 * is on roaming, in which case we will also be given new keys.
2337 * Keep the below message for now, unless it starts bothering
2338 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002339 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002340 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002341 wl1271_info("JOIN while associated.");
2342
Eliad Peller5ec8a442012-02-02 12:22:09 +02002343 /* clear encryption type */
2344 wlvif->encryption_type = KEY_NONE;
2345
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002346 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002347 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002348
Eliad Peller227e81e2011-08-14 13:17:26 +03002349 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002350 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002351 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002352 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002353 if (ret < 0)
2354 goto out;
2355
Eliad Pellerba8447f2011-10-10 10:13:00 +02002356 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002357 goto out;
2358
2359 /*
2360 * The join command disable the keep-alive mode, shut down its process,
2361 * and also clear the template config, so we need to reset it all after
2362 * the join. The acx_aid starts the keep-alive process, and the order
2363 * of the commands below is relevant.
2364 */
Eliad Peller0603d892011-10-05 11:55:51 +02002365 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002366 if (ret < 0)
2367 goto out;
2368
Eliad Peller0603d892011-10-05 11:55:51 +02002369 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002370 if (ret < 0)
2371 goto out;
2372
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002373 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002374 if (ret < 0)
2375 goto out;
2376
Eliad Peller0603d892011-10-05 11:55:51 +02002377 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2378 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002379 ACX_KEEP_ALIVE_TPL_VALID);
2380 if (ret < 0)
2381 goto out;
2382
2383out:
2384 return ret;
2385}
2386
Eliad Peller0603d892011-10-05 11:55:51 +02002387static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002388{
2389 int ret;
2390
Eliad Peller52630c52011-10-10 10:13:08 +02002391 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002392 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2393
Shahar Levi6d158ff2011-09-08 13:01:33 +03002394 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002395 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002396 }
2397
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002398 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002399 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002400 if (ret < 0)
2401 goto out;
2402
Oz Krakowskib992c682011-06-26 10:36:02 +03002403 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002404 wlvif->tx_security_last_seq_lsb = 0;
2405 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002406
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002407out:
2408 return ret;
2409}
2410
Eliad Peller87fbcb02011-10-05 11:55:41 +02002411static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002412{
Eliad Peller1b92f152011-10-10 10:13:09 +02002413 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002414 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002415}
2416
Eliad Peller87fbcb02011-10-05 11:55:41 +02002417static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2418 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002419{
2420 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002421 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2422
2423 if (idle == cur_idle)
2424 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002425
2426 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002427 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002428 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002429 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002430 if (ret < 0)
2431 goto out;
2432 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002433 wlvif->rate_set =
2434 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2435 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002436 if (ret < 0)
2437 goto out;
2438 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002439 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002440 ACX_KEEP_ALIVE_TPL_INVALID);
2441 if (ret < 0)
2442 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002443 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002444 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002445 /* The current firmware only supports sched_scan in idle */
2446 if (wl->sched_scanning) {
2447 wl1271_scan_sched_scan_stop(wl);
2448 ieee80211_sched_scan_stopped(wl->hw);
2449 }
2450
Eliad Peller679a6732011-10-11 11:55:44 +02002451 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002452 if (ret < 0)
2453 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002454 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002455 }
2456
2457out:
2458 return ret;
2459}
2460
Eliad Peller9f259c42011-10-10 10:13:12 +02002461static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2462 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002463{
Eliad Peller9f259c42011-10-10 10:13:12 +02002464 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2465 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002466
2467 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2468
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002469 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002470 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002471 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002472 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002473 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002474 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002475 wlvif->band = conf->channel->band;
2476 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002477
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002478 if (!is_ap) {
2479 /*
2480 * FIXME: the mac80211 should really provide a fixed
2481 * rate to use here. for now, just use the smallest
2482 * possible rate for the band as a fixed rate for
2483 * association frames and other control messages.
2484 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002485 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002486 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002487
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002488 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002489 wl1271_tx_min_rate_get(wl,
2490 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002491 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002492 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002493 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002494 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002495
Eliad Pellerba8447f2011-10-10 10:13:00 +02002496 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2497 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002498 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002499 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002500 ret = wl12xx_croc(wl,
2501 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002502 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002503 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002504 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002505 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002506 if (ret < 0)
2507 wl1271_warning("cmd join on channel "
2508 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002509 } else {
2510 /*
2511 * change the ROC channel. do it only if we are
2512 * not idle. otherwise, CROC will be called
2513 * anyway.
2514 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002515 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002516 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002517 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002518 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002519 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002520
Eliad Peller679a6732011-10-11 11:55:44 +02002521 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002522 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002523 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002524 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002525 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002526 }
2527 }
2528
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002529 if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002530
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002531 if ((conf->flags & IEEE80211_CONF_PS) &&
2532 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002533 !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002534
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002535 int ps_mode;
2536 char *ps_mode_str;
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002537
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002538 if (wl->conf.conn.forced_ps) {
2539 ps_mode = STATION_POWER_SAVE_MODE;
2540 ps_mode_str = "forced";
2541 } else {
2542 ps_mode = STATION_AUTO_PS_MODE;
2543 ps_mode_str = "auto";
2544 }
2545
2546 wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
2547
2548 ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
2549
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002550 if (ret < 0)
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002551 wl1271_warning("enter %s ps failed %d",
2552 ps_mode_str, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002553
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002554 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002555 test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002556
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002557 wl1271_debug(DEBUG_PSM, "auto ps disabled");
2558
Eliad Peller0603d892011-10-05 11:55:51 +02002559 ret = wl1271_ps_set_mode(wl, wlvif,
Eyal Shapira248a0012012-01-31 11:57:23 +02002560 STATION_ACTIVE_MODE);
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002561 if (ret < 0)
2562 wl1271_warning("exit auto ps failed %d", ret);
2563 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002564 }
2565
Eliad Peller6bd65022011-10-10 10:13:11 +02002566 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002567 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002568 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002569 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002570
Eliad Peller6bd65022011-10-10 10:13:11 +02002571 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002572 }
2573
Eliad Peller9f259c42011-10-10 10:13:12 +02002574 return 0;
2575}
2576
2577static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2578{
2579 struct wl1271 *wl = hw->priv;
2580 struct wl12xx_vif *wlvif;
2581 struct ieee80211_conf *conf = &hw->conf;
2582 int channel, ret = 0;
2583
2584 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2585
2586 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2587 " changed 0x%x",
2588 channel,
2589 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2590 conf->power_level,
2591 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2592 changed);
2593
2594 /*
2595 * mac80211 will go to idle nearly immediately after transmitting some
2596 * frames, such as the deauth. To make sure those frames reach the air,
2597 * wait here until the TX queue is fully flushed.
2598 */
2599 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2600 (conf->flags & IEEE80211_CONF_IDLE))
2601 wl1271_tx_flush(wl);
2602
2603 mutex_lock(&wl->mutex);
2604
2605 /* we support configuring the channel and band even while off */
2606 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2607 wl->band = conf->channel->band;
2608 wl->channel = channel;
2609 }
2610
2611 if (changed & IEEE80211_CONF_CHANGE_POWER)
2612 wl->power_level = conf->power_level;
2613
2614 if (unlikely(wl->state == WL1271_STATE_OFF))
2615 goto out;
2616
2617 ret = wl1271_ps_elp_wakeup(wl);
2618 if (ret < 0)
2619 goto out;
2620
2621 /* configure each interface */
2622 wl12xx_for_each_wlvif(wl, wlvif) {
2623 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2624 if (ret < 0)
2625 goto out_sleep;
2626 }
2627
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002628out_sleep:
2629 wl1271_ps_elp_sleep(wl);
2630
2631out:
2632 mutex_unlock(&wl->mutex);
2633
2634 return ret;
2635}
2636
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002637struct wl1271_filter_params {
2638 bool enabled;
2639 int mc_list_length;
2640 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2641};
2642
Jiri Pirko22bedad2010-04-01 21:22:57 +00002643static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2644 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002645{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002646 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002647 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002648 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002649
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002650 if (unlikely(wl->state == WL1271_STATE_OFF))
2651 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002652
Juuso Oikarinen74441132009-10-13 12:47:53 +03002653 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002654 if (!fp) {
2655 wl1271_error("Out of memory setting filters.");
2656 return 0;
2657 }
2658
2659 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002660 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002661 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2662 fp->enabled = false;
2663 } else {
2664 fp->enabled = true;
2665 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002666 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002667 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002668 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002669 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002670 }
2671
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002672 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002673}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002674
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002675#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2676 FIF_ALLMULTI | \
2677 FIF_FCSFAIL | \
2678 FIF_BCN_PRBRESP_PROMISC | \
2679 FIF_CONTROL | \
2680 FIF_OTHER_BSS)
2681
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002682static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2683 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002684 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002685{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002686 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002687 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002688 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002689
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002690 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002691
Arik Nemtsov7d057862010-10-16 19:25:35 +02002692 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2693 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002694
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002695 mutex_lock(&wl->mutex);
2696
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002697 *total &= WL1271_SUPPORTED_FILTERS;
2698 changed &= WL1271_SUPPORTED_FILTERS;
2699
2700 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002701 goto out;
2702
Ido Yariva6208652011-03-01 15:14:41 +02002703 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002704 if (ret < 0)
2705 goto out;
2706
Eliad Peller6e8cd332011-10-10 10:13:13 +02002707 wl12xx_for_each_wlvif(wl, wlvif) {
2708 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2709 if (*total & FIF_ALLMULTI)
2710 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2711 false,
2712 NULL, 0);
2713 else if (fp)
2714 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2715 fp->enabled,
2716 fp->mc_list,
2717 fp->mc_list_length);
2718 if (ret < 0)
2719 goto out_sleep;
2720 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002721 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002722
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002723 /*
2724 * the fw doesn't provide an api to configure the filters. instead,
2725 * the filters configuration is based on the active roles / ROC
2726 * state.
2727 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002728
2729out_sleep:
2730 wl1271_ps_elp_sleep(wl);
2731
2732out:
2733 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002734 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002735}
2736
Eliad Peller170d0e62011-10-05 11:56:06 +02002737static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2738 u8 id, u8 key_type, u8 key_size,
2739 const u8 *key, u8 hlid, u32 tx_seq_32,
2740 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002741{
2742 struct wl1271_ap_key *ap_key;
2743 int i;
2744
2745 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2746
2747 if (key_size > MAX_KEY_SIZE)
2748 return -EINVAL;
2749
2750 /*
2751 * Find next free entry in ap_keys. Also check we are not replacing
2752 * an existing key.
2753 */
2754 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002755 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002756 break;
2757
Eliad Peller170d0e62011-10-05 11:56:06 +02002758 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002759 wl1271_warning("trying to record key replacement");
2760 return -EINVAL;
2761 }
2762 }
2763
2764 if (i == MAX_NUM_KEYS)
2765 return -EBUSY;
2766
2767 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2768 if (!ap_key)
2769 return -ENOMEM;
2770
2771 ap_key->id = id;
2772 ap_key->key_type = key_type;
2773 ap_key->key_size = key_size;
2774 memcpy(ap_key->key, key, key_size);
2775 ap_key->hlid = hlid;
2776 ap_key->tx_seq_32 = tx_seq_32;
2777 ap_key->tx_seq_16 = tx_seq_16;
2778
Eliad Peller170d0e62011-10-05 11:56:06 +02002779 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002780 return 0;
2781}
2782
Eliad Peller170d0e62011-10-05 11:56:06 +02002783static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002784{
2785 int i;
2786
2787 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002788 kfree(wlvif->ap.recorded_keys[i]);
2789 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002790 }
2791}
2792
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002793static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002794{
2795 int i, ret = 0;
2796 struct wl1271_ap_key *key;
2797 bool wep_key_added = false;
2798
2799 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002800 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002801 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002802 break;
2803
Eliad Peller170d0e62011-10-05 11:56:06 +02002804 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002805 hlid = key->hlid;
2806 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002807 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002808
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002809 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002810 key->id, key->key_type,
2811 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002812 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002813 key->tx_seq_16);
2814 if (ret < 0)
2815 goto out;
2816
2817 if (key->key_type == KEY_WEP)
2818 wep_key_added = true;
2819 }
2820
2821 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002822 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002823 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002824 if (ret < 0)
2825 goto out;
2826 }
2827
2828out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002829 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002830 return ret;
2831}
2832
Eliad Peller536129c2011-10-05 11:55:45 +02002833static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2834 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002835 u8 key_size, const u8 *key, u32 tx_seq_32,
2836 u16 tx_seq_16, struct ieee80211_sta *sta)
2837{
2838 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002839 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002840
2841 if (is_ap) {
2842 struct wl1271_station *wl_sta;
2843 u8 hlid;
2844
2845 if (sta) {
2846 wl_sta = (struct wl1271_station *)sta->drv_priv;
2847 hlid = wl_sta->hlid;
2848 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002849 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002850 }
2851
Eliad Peller53d40d02011-10-10 10:13:02 +02002852 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002853 /*
2854 * We do not support removing keys after AP shutdown.
2855 * Pretend we do to make mac80211 happy.
2856 */
2857 if (action != KEY_ADD_OR_REPLACE)
2858 return 0;
2859
Eliad Peller170d0e62011-10-05 11:56:06 +02002860 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002861 key_type, key_size,
2862 key, hlid, tx_seq_32,
2863 tx_seq_16);
2864 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002865 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002866 id, key_type, key_size,
2867 key, hlid, tx_seq_32,
2868 tx_seq_16);
2869 }
2870
2871 if (ret < 0)
2872 return ret;
2873 } else {
2874 const u8 *addr;
2875 static const u8 bcast_addr[ETH_ALEN] = {
2876 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2877 };
2878
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002879 /*
2880 * A STA set to GEM cipher requires 2 tx spare blocks.
2881 * Return to default value when GEM cipher key is removed
2882 */
2883 if (key_type == KEY_GEM) {
2884 if (action == KEY_ADD_OR_REPLACE)
2885 wl->tx_spare_blocks = 2;
2886 else if (action == KEY_REMOVE)
2887 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2888 }
2889
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002890 addr = sta ? sta->addr : bcast_addr;
2891
2892 if (is_zero_ether_addr(addr)) {
2893 /* We dont support TX only encryption */
2894 return -EOPNOTSUPP;
2895 }
2896
2897 /* The wl1271 does not allow to remove unicast keys - they
2898 will be cleared automatically on next CMD_JOIN. Ignore the
2899 request silently, as we dont want the mac80211 to emit
2900 an error message. */
2901 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2902 return 0;
2903
Eliad Peller010d3d32011-08-14 13:17:31 +03002904 /* don't remove key if hlid was already deleted */
2905 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002906 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002907 return 0;
2908
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002909 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002910 id, key_type, key_size,
2911 key, addr, tx_seq_32,
2912 tx_seq_16);
2913 if (ret < 0)
2914 return ret;
2915
2916 /* the default WEP key needs to be configured at least once */
2917 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002918 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002919 wlvif->default_key,
2920 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002921 if (ret < 0)
2922 return ret;
2923 }
2924 }
2925
2926 return 0;
2927}
2928
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002929static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2930 struct ieee80211_vif *vif,
2931 struct ieee80211_sta *sta,
2932 struct ieee80211_key_conf *key_conf)
2933{
2934 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002935 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002936 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002937 u32 tx_seq_32 = 0;
2938 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002939 u8 key_type;
2940
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002941 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2942
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002943 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002944 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002945 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002946 key_conf->keylen, key_conf->flags);
2947 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2948
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002949 mutex_lock(&wl->mutex);
2950
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002951 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2952 ret = -EAGAIN;
2953 goto out_unlock;
2954 }
2955
Ido Yariva6208652011-03-01 15:14:41 +02002956 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002957 if (ret < 0)
2958 goto out_unlock;
2959
Johannes Berg97359d12010-08-10 09:46:38 +02002960 switch (key_conf->cipher) {
2961 case WLAN_CIPHER_SUITE_WEP40:
2962 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002963 key_type = KEY_WEP;
2964
2965 key_conf->hw_key_idx = key_conf->keyidx;
2966 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002967 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002968 key_type = KEY_TKIP;
2969
2970 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002971 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2972 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002973 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002974 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002975 key_type = KEY_AES;
2976
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002977 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
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);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002980 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002981 case WL1271_CIPHER_SUITE_GEM:
2982 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002983 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2984 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002985 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002986 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002987 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002988
2989 ret = -EOPNOTSUPP;
2990 goto out_sleep;
2991 }
2992
2993 switch (cmd) {
2994 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002995 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002996 key_conf->keyidx, key_type,
2997 key_conf->keylen, key_conf->key,
2998 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002999 if (ret < 0) {
3000 wl1271_error("Could not add or replace key");
3001 goto out_sleep;
3002 }
Eliad Peller5ec8a442012-02-02 12:22:09 +02003003
3004 /*
3005 * reconfiguring arp response if the unicast (or common)
3006 * encryption key type was changed
3007 */
3008 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
3009 (sta || key_type == KEY_WEP) &&
3010 wlvif->encryption_type != key_type) {
3011 wlvif->encryption_type = key_type;
3012 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
3013 if (ret < 0) {
3014 wl1271_warning("build arp rsp failed: %d", ret);
3015 goto out_sleep;
3016 }
3017 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003018 break;
3019
3020 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003021 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003022 key_conf->keyidx, key_type,
3023 key_conf->keylen, key_conf->key,
3024 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003025 if (ret < 0) {
3026 wl1271_error("Could not remove key");
3027 goto out_sleep;
3028 }
3029 break;
3030
3031 default:
3032 wl1271_error("Unsupported key cmd 0x%x", cmd);
3033 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003034 break;
3035 }
3036
3037out_sleep:
3038 wl1271_ps_elp_sleep(wl);
3039
3040out_unlock:
3041 mutex_unlock(&wl->mutex);
3042
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003043 return ret;
3044}
3045
3046static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003047 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003048 struct cfg80211_scan_request *req)
3049{
3050 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003051 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3052
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003053 int ret;
3054 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003055 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003056
3057 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3058
3059 if (req->n_ssids) {
3060 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003061 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003062 }
3063
3064 mutex_lock(&wl->mutex);
3065
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003066 if (wl->state == WL1271_STATE_OFF) {
3067 /*
3068 * We cannot return -EBUSY here because cfg80211 will expect
3069 * a call to ieee80211_scan_completed if we do - in this case
3070 * there won't be any call.
3071 */
3072 ret = -EAGAIN;
3073 goto out;
3074 }
3075
Ido Yariva6208652011-03-01 15:14:41 +02003076 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003077 if (ret < 0)
3078 goto out;
3079
Eliad Peller92e712d2011-12-18 20:25:43 +02003080 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
3081 test_bit(wlvif->role_id, wl->roc_map)) {
3082 /* don't allow scanning right now */
3083 ret = -EBUSY;
3084 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003085 }
3086
Eliad Peller784f6942011-10-05 11:55:39 +02003087 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003088out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003089 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003090out:
3091 mutex_unlock(&wl->mutex);
3092
3093 return ret;
3094}
3095
Eliad Peller73ecce32011-06-27 13:06:45 +03003096static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3097 struct ieee80211_vif *vif)
3098{
3099 struct wl1271 *wl = hw->priv;
3100 int ret;
3101
3102 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3103
3104 mutex_lock(&wl->mutex);
3105
3106 if (wl->state == WL1271_STATE_OFF)
3107 goto out;
3108
3109 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3110 goto out;
3111
3112 ret = wl1271_ps_elp_wakeup(wl);
3113 if (ret < 0)
3114 goto out;
3115
3116 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3117 ret = wl1271_scan_stop(wl);
3118 if (ret < 0)
3119 goto out_sleep;
3120 }
3121 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3122 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003123 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003124 wl->scan.req = NULL;
3125 ieee80211_scan_completed(wl->hw, true);
3126
3127out_sleep:
3128 wl1271_ps_elp_sleep(wl);
3129out:
3130 mutex_unlock(&wl->mutex);
3131
3132 cancel_delayed_work_sync(&wl->scan_complete_work);
3133}
3134
Luciano Coelho33c2c062011-05-10 14:46:02 +03003135static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3136 struct ieee80211_vif *vif,
3137 struct cfg80211_sched_scan_request *req,
3138 struct ieee80211_sched_scan_ies *ies)
3139{
3140 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003141 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003142 int ret;
3143
3144 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3145
3146 mutex_lock(&wl->mutex);
3147
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003148 if (wl->state == WL1271_STATE_OFF) {
3149 ret = -EAGAIN;
3150 goto out;
3151 }
3152
Luciano Coelho33c2c062011-05-10 14:46:02 +03003153 ret = wl1271_ps_elp_wakeup(wl);
3154 if (ret < 0)
3155 goto out;
3156
Eliad Peller536129c2011-10-05 11:55:45 +02003157 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003158 if (ret < 0)
3159 goto out_sleep;
3160
Eliad Peller536129c2011-10-05 11:55:45 +02003161 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003162 if (ret < 0)
3163 goto out_sleep;
3164
3165 wl->sched_scanning = true;
3166
3167out_sleep:
3168 wl1271_ps_elp_sleep(wl);
3169out:
3170 mutex_unlock(&wl->mutex);
3171 return ret;
3172}
3173
3174static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3175 struct ieee80211_vif *vif)
3176{
3177 struct wl1271 *wl = hw->priv;
3178 int ret;
3179
3180 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3181
3182 mutex_lock(&wl->mutex);
3183
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003184 if (wl->state == WL1271_STATE_OFF)
3185 goto out;
3186
Luciano Coelho33c2c062011-05-10 14:46:02 +03003187 ret = wl1271_ps_elp_wakeup(wl);
3188 if (ret < 0)
3189 goto out;
3190
3191 wl1271_scan_sched_scan_stop(wl);
3192
3193 wl1271_ps_elp_sleep(wl);
3194out:
3195 mutex_unlock(&wl->mutex);
3196}
3197
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003198static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3199{
3200 struct wl1271 *wl = hw->priv;
3201 int ret = 0;
3202
3203 mutex_lock(&wl->mutex);
3204
3205 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3206 ret = -EAGAIN;
3207 goto out;
3208 }
3209
Ido Yariva6208652011-03-01 15:14:41 +02003210 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003211 if (ret < 0)
3212 goto out;
3213
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003214 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003215 if (ret < 0)
3216 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3217
3218 wl1271_ps_elp_sleep(wl);
3219
3220out:
3221 mutex_unlock(&wl->mutex);
3222
3223 return ret;
3224}
3225
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003226static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3227{
3228 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003229 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003230 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003231
3232 mutex_lock(&wl->mutex);
3233
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003234 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3235 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003236 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003237 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003238
Ido Yariva6208652011-03-01 15:14:41 +02003239 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003240 if (ret < 0)
3241 goto out;
3242
Eliad Peller6e8cd332011-10-10 10:13:13 +02003243 wl12xx_for_each_wlvif(wl, wlvif) {
3244 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3245 if (ret < 0)
3246 wl1271_warning("set rts threshold failed: %d", ret);
3247 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003248 wl1271_ps_elp_sleep(wl);
3249
3250out:
3251 mutex_unlock(&wl->mutex);
3252
3253 return ret;
3254}
3255
Eliad Peller1fe9f162011-10-05 11:55:48 +02003256static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003257 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003258{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003259 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003260 u8 ssid_len;
3261 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3262 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003263
Eliad Peller889cb362011-05-01 09:56:45 +03003264 if (!ptr) {
3265 wl1271_error("No SSID in IEs!");
3266 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003267 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003268
Eliad Peller889cb362011-05-01 09:56:45 +03003269 ssid_len = ptr[1];
3270 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3271 wl1271_error("SSID is too long!");
3272 return -EINVAL;
3273 }
3274
Eliad Peller1fe9f162011-10-05 11:55:48 +02003275 wlvif->ssid_len = ssid_len;
3276 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003277 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003278}
3279
Eliad Pellerd48055d2011-09-15 12:07:04 +03003280static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3281{
3282 int len;
3283 const u8 *next, *end = skb->data + skb->len;
3284 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3285 skb->len - ieoffset);
3286 if (!ie)
3287 return;
3288 len = ie[1] + 2;
3289 next = ie + len;
3290 memmove(ie, next, end - next);
3291 skb_trim(skb, skb->len - len);
3292}
3293
Eliad Peller26b4bf22011-09-15 12:07:05 +03003294static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3295 unsigned int oui, u8 oui_type,
3296 int ieoffset)
3297{
3298 int len;
3299 const u8 *next, *end = skb->data + skb->len;
3300 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3301 skb->data + ieoffset,
3302 skb->len - ieoffset);
3303 if (!ie)
3304 return;
3305 len = ie[1] + 2;
3306 next = ie + len;
3307 memmove(ie, next, end - next);
3308 skb_trim(skb, skb->len - len);
3309}
3310
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003311static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3312 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003313{
Eliad Pellercdaac622012-01-31 11:57:16 +02003314 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003315 struct sk_buff *skb;
3316 int ret;
3317
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003318 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003319 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003320 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003321
Eliad Pellercdaac622012-01-31 11:57:16 +02003322 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov560f0022011-11-08 18:46:54 +02003323 CMD_TEMPL_AP_PROBE_RESPONSE,
3324 skb->data,
3325 skb->len, 0,
3326 rates);
3327
3328 dev_kfree_skb(skb);
3329 return ret;
3330}
3331
3332static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3333 struct ieee80211_vif *vif,
3334 u8 *probe_rsp_data,
3335 size_t probe_rsp_len,
3336 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003337{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003338 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3339 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003340 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3341 int ssid_ie_offset, ie_offset, templ_len;
3342 const u8 *ptr;
3343
3344 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003345 if (wlvif->ssid_len > 0)
Eliad Pellercdaac622012-01-31 11:57:16 +02003346 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003347 CMD_TEMPL_AP_PROBE_RESPONSE,
3348 probe_rsp_data,
3349 probe_rsp_len, 0,
3350 rates);
3351
3352 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3353 wl1271_error("probe_rsp template too big");
3354 return -EINVAL;
3355 }
3356
3357 /* start searching from IE offset */
3358 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3359
3360 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3361 probe_rsp_len - ie_offset);
3362 if (!ptr) {
3363 wl1271_error("No SSID in beacon!");
3364 return -EINVAL;
3365 }
3366
3367 ssid_ie_offset = ptr - probe_rsp_data;
3368 ptr += (ptr[1] + 2);
3369
3370 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3371
3372 /* insert SSID from bss_conf */
3373 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3374 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3375 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3376 bss_conf->ssid, bss_conf->ssid_len);
3377 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3378
3379 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3380 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3381 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3382
Eliad Pellercdaac622012-01-31 11:57:16 +02003383 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003384 CMD_TEMPL_AP_PROBE_RESPONSE,
3385 probe_rsp_templ,
3386 templ_len, 0,
3387 rates);
3388}
3389
Arik Nemtsove78a2872010-10-16 19:07:21 +02003390static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003391 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003392 struct ieee80211_bss_conf *bss_conf,
3393 u32 changed)
3394{
Eliad Peller0603d892011-10-05 11:55:51 +02003395 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003396 int ret = 0;
3397
3398 if (changed & BSS_CHANGED_ERP_SLOT) {
3399 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003400 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003401 else
Eliad Peller0603d892011-10-05 11:55:51 +02003402 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003403 if (ret < 0) {
3404 wl1271_warning("Set slot time failed %d", ret);
3405 goto out;
3406 }
3407 }
3408
3409 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3410 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003411 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003412 else
Eliad Peller0603d892011-10-05 11:55:51 +02003413 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003414 }
3415
3416 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3417 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003418 ret = wl1271_acx_cts_protect(wl, wlvif,
3419 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003420 else
Eliad Peller0603d892011-10-05 11:55:51 +02003421 ret = wl1271_acx_cts_protect(wl, wlvif,
3422 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003423 if (ret < 0) {
3424 wl1271_warning("Set ctsprotect failed %d", ret);
3425 goto out;
3426 }
3427 }
3428
3429out:
3430 return ret;
3431}
3432
3433static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3434 struct ieee80211_vif *vif,
3435 struct ieee80211_bss_conf *bss_conf,
3436 u32 changed)
3437{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003438 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003439 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003440 int ret = 0;
3441
3442 if ((changed & BSS_CHANGED_BEACON_INT)) {
3443 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3444 bss_conf->beacon_int);
3445
Eliad Peller6a899792011-10-05 11:55:58 +02003446 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003447 }
3448
Arik Nemtsov560f0022011-11-08 18:46:54 +02003449 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3450 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003451 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3452 wl1271_debug(DEBUG_AP, "probe response updated");
3453 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3454 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003455 }
3456
Arik Nemtsove78a2872010-10-16 19:07:21 +02003457 if ((changed & BSS_CHANGED_BEACON)) {
3458 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003459 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003460 int ieoffset = offsetof(struct ieee80211_mgmt,
3461 u.beacon.variable);
3462 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3463 u16 tmpl_id;
3464
Arik Nemtsov560f0022011-11-08 18:46:54 +02003465 if (!beacon) {
3466 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003467 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003468 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003469
3470 wl1271_debug(DEBUG_MASTER, "beacon updated");
3471
Eliad Peller1fe9f162011-10-05 11:55:48 +02003472 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003473 if (ret < 0) {
3474 dev_kfree_skb(beacon);
3475 goto out;
3476 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003477 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003478 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3479 CMD_TEMPL_BEACON;
Eliad Pellercdaac622012-01-31 11:57:16 +02003480 ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003481 beacon->data,
3482 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003483 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003484 if (ret < 0) {
3485 dev_kfree_skb(beacon);
3486 goto out;
3487 }
3488
Arik Nemtsov560f0022011-11-08 18:46:54 +02003489 /*
3490 * In case we already have a probe-resp beacon set explicitly
3491 * by usermode, don't use the beacon data.
3492 */
3493 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3494 goto end_bcn;
3495
Eliad Pellerd48055d2011-09-15 12:07:04 +03003496 /* remove TIM ie from probe response */
3497 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3498
Eliad Peller26b4bf22011-09-15 12:07:05 +03003499 /*
3500 * remove p2p ie from probe response.
3501 * the fw reponds to probe requests that don't include
3502 * the p2p ie. probe requests with p2p ie will be passed,
3503 * and will be responded by the supplicant (the spec
3504 * forbids including the p2p ie when responding to probe
3505 * requests that didn't include it).
3506 */
3507 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3508 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3509
Arik Nemtsove78a2872010-10-16 19:07:21 +02003510 hdr = (struct ieee80211_hdr *) beacon->data;
3511 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3512 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003513 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003514 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003515 beacon->data,
3516 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003517 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003518 else
Eliad Pellercdaac622012-01-31 11:57:16 +02003519 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003520 CMD_TEMPL_PROBE_RESPONSE,
3521 beacon->data,
3522 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003523 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003524end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003525 dev_kfree_skb(beacon);
3526 if (ret < 0)
3527 goto out;
3528 }
3529
3530out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003531 if (ret != 0)
3532 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003533 return ret;
3534}
3535
3536/* AP mode changes */
3537static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003538 struct ieee80211_vif *vif,
3539 struct ieee80211_bss_conf *bss_conf,
3540 u32 changed)
3541{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003542 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003543 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003544
Arik Nemtsove78a2872010-10-16 19:07:21 +02003545 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3546 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003547
Eliad Peller87fbcb02011-10-05 11:55:41 +02003548 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003549 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003550 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003551 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003552
Eliad Peller87fbcb02011-10-05 11:55:41 +02003553 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003554 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003555 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003556 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003557 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003558
Eliad Peller784f6942011-10-05 11:55:39 +02003559 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003560 if (ret < 0)
3561 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003562 }
3563
Arik Nemtsove78a2872010-10-16 19:07:21 +02003564 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3565 if (ret < 0)
3566 goto out;
3567
3568 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3569 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003570 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003571 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003572 if (ret < 0)
3573 goto out;
3574
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003575 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003576 if (ret < 0)
3577 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003578
Eliad Peller53d40d02011-10-10 10:13:02 +02003579 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003580 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003581 }
3582 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003583 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003584 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003585 if (ret < 0)
3586 goto out;
3587
Eliad Peller53d40d02011-10-10 10:13:02 +02003588 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003589 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3590 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003591 wl1271_debug(DEBUG_AP, "stopped AP");
3592 }
3593 }
3594 }
3595
Eliad Peller0603d892011-10-05 11:55:51 +02003596 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003597 if (ret < 0)
3598 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003599
3600 /* Handle HT information change */
3601 if ((changed & BSS_CHANGED_HT) &&
3602 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003603 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003604 bss_conf->ht_operation_mode);
3605 if (ret < 0) {
3606 wl1271_warning("Set ht information failed %d", ret);
3607 goto out;
3608 }
3609 }
3610
Arik Nemtsove78a2872010-10-16 19:07:21 +02003611out:
3612 return;
3613}
3614
3615/* STA/IBSS mode changes */
3616static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3617 struct ieee80211_vif *vif,
3618 struct ieee80211_bss_conf *bss_conf,
3619 u32 changed)
3620{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003621 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003622 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003623 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003624 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003625 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003626 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003627 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003628 bool sta_exists = false;
3629 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003630
3631 if (is_ibss) {
3632 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3633 changed);
3634 if (ret < 0)
3635 goto out;
3636 }
3637
Eliad Peller227e81e2011-08-14 13:17:26 +03003638 if (changed & BSS_CHANGED_IBSS) {
3639 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003640 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003641 ibss_joined = true;
3642 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003643 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3644 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003645 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003646 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003647 }
3648 }
3649 }
3650
3651 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003652 do_join = true;
3653
3654 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003655 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003656 do_join = true;
3657
Eliad Peller227e81e2011-08-14 13:17:26 +03003658 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003659 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3660 bss_conf->enable_beacon ? "enabled" : "disabled");
3661
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003662 do_join = true;
3663 }
3664
Eliad Pellerc31e4942011-10-23 08:21:55 +02003665 if (changed & BSS_CHANGED_IDLE) {
3666 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3667 if (ret < 0)
3668 wl1271_warning("idle mode change failed %d", ret);
3669 }
3670
Arik Nemtsove78a2872010-10-16 19:07:21 +02003671 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003672 bool enable = false;
3673 if (bss_conf->cqm_rssi_thold)
3674 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003675 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003676 bss_conf->cqm_rssi_thold,
3677 bss_conf->cqm_rssi_hyst);
3678 if (ret < 0)
3679 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003680 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003681 }
3682
Eliad Peller7db4ee62012-01-24 18:18:42 +02003683 if (changed & BSS_CHANGED_BSSID &&
3684 (is_ibss || bss_conf->assoc))
Eliad Pellercdf09492011-10-05 11:55:44 +02003685 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003686 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003687 if (ret < 0)
3688 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003689
Eliad Peller784f6942011-10-05 11:55:39 +02003690 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003691 if (ret < 0)
3692 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003693
Eliad Pellerfa287b82010-12-26 09:27:50 +01003694 /* Need to update the BSSID (for filtering etc) */
3695 do_join = true;
3696 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003697
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003698 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3699 rcu_read_lock();
3700 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3701 if (!sta)
3702 goto sta_not_found;
3703
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003704 /* save the supp_rates of the ap */
3705 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3706 if (sta->ht_cap.ht_supported)
3707 sta_rate_set |=
3708 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003709 sta_ht_cap = sta->ht_cap;
3710 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003711
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003712sta_not_found:
3713 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003714 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003715
Arik Nemtsove78a2872010-10-16 19:07:21 +02003716 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003717 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003718 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003719 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003720 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003721 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003722
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003723 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003724 * use basic rates from AP, and determine lowest rate
3725 * to use with control frames.
3726 */
3727 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003728 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003729 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003730 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003731 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003732 wl1271_tx_min_rate_get(wl,
3733 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003734 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003735 wlvif->rate_set =
3736 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003737 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003738 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003739 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003740 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003741 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003742
3743 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003744 * with wl1271, we don't need to update the
3745 * beacon_int and dtim_period, because the firmware
3746 * updates it by itself when the first beacon is
3747 * received after a join.
3748 */
Eliad Peller6840e372011-10-05 11:55:50 +02003749 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003750 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003751 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003752
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003753 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003754 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003755 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003756 dev_kfree_skb(wlvif->probereq);
3757 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003758 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003759 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003760 ieoffset = offsetof(struct ieee80211_mgmt,
3761 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003762 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003763
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003764 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003765 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003766 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003767 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003768 } else {
3769 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003770 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003771 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3772 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003773 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003774 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3775 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003776 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003777
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003778 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003779 dev_kfree_skb(wlvif->probereq);
3780 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003781
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003782 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003783 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003784 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003785 wl1271_tx_min_rate_get(wl,
3786 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003787 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003788 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003789 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003790
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003791 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003792 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003793
3794 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003795 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003796 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003797 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003798
3799 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003800 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003801 u32 conf_flags = wl->hw->conf.flags;
3802 /*
3803 * we might have to disable roc, if there was
3804 * no IF_OPER_UP notification.
3805 */
3806 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003807 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003808 if (ret < 0)
3809 goto out;
3810 }
3811 /*
3812 * (we also need to disable roc in case of
3813 * roaming on the same channel. until we will
3814 * have a better flow...)
3815 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003816 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3817 ret = wl12xx_croc(wl,
3818 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003819 if (ret < 0)
3820 goto out;
3821 }
3822
Eliad Peller0603d892011-10-05 11:55:51 +02003823 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003824 if (!(conf_flags & IEEE80211_CONF_IDLE))
3825 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003826 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003827 }
3828 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003829
Eliad Pellerd192d262011-05-24 14:33:08 +03003830 if (changed & BSS_CHANGED_IBSS) {
3831 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3832 bss_conf->ibss_joined);
3833
3834 if (bss_conf->ibss_joined) {
3835 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003836 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003837 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003838 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003839 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003840 wl1271_tx_min_rate_get(wl,
3841 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003842
Shahar Levi06b660e2011-09-05 13:54:36 +03003843 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003844 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3845 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003846 if (ret < 0)
3847 goto out;
3848 }
3849 }
3850
Eliad Peller0603d892011-10-05 11:55:51 +02003851 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003852 if (ret < 0)
3853 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003854
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003855 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003856 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003857 if (ret < 0) {
3858 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003859 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003860 }
Eliad Peller251c1772011-08-14 13:17:17 +03003861
3862 /* ROC until connected (after EAPOL exchange) */
3863 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003864 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003865 if (ret < 0)
3866 goto out;
3867
Eliad Pellerba8447f2011-10-10 10:13:00 +02003868 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003869 ieee80211_get_operstate(vif));
3870 }
3871 /*
3872 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003873 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003874 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003875 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003876 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003877 if (ret < 0)
3878 goto out;
3879 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003880 }
3881
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003882 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003883 if (sta_exists) {
3884 if ((changed & BSS_CHANGED_HT) &&
3885 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003886 ret = wl1271_acx_set_ht_capabilities(wl,
3887 &sta_ht_cap,
3888 true,
Eliad Peller154da672011-10-05 11:55:53 +02003889 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003890 if (ret < 0) {
3891 wl1271_warning("Set ht cap true failed %d",
3892 ret);
3893 goto out;
3894 }
3895 }
3896 /* handle new association without HT and disassociation */
3897 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003898 ret = wl1271_acx_set_ht_capabilities(wl,
3899 &sta_ht_cap,
3900 false,
Eliad Peller154da672011-10-05 11:55:53 +02003901 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003902 if (ret < 0) {
3903 wl1271_warning("Set ht cap false failed %d",
3904 ret);
3905 goto out;
3906 }
3907 }
3908 }
3909
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003910 /* Handle HT information change. Done after join. */
3911 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003912 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003913 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003914 bss_conf->ht_operation_mode);
3915 if (ret < 0) {
3916 wl1271_warning("Set ht information failed %d", ret);
3917 goto out;
3918 }
3919 }
3920
Eliad Peller76a74c82012-02-02 12:22:11 +02003921 /* Handle arp filtering. Done after join. */
3922 if ((changed & BSS_CHANGED_ARP_FILTER) ||
3923 (!is_ibss && (changed & BSS_CHANGED_QOS))) {
3924 __be32 addr = bss_conf->arp_addr_list[0];
3925 wlvif->sta.qos = bss_conf->qos;
3926 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
3927
3928 if (bss_conf->arp_addr_cnt == 1 &&
3929 bss_conf->arp_filter_enabled) {
3930 wlvif->ip_addr = addr;
3931 /*
3932 * The template should have been configured only upon
3933 * association. however, it seems that the correct ip
3934 * isn't being set (when sending), so we have to
3935 * reconfigure the template upon every ip change.
3936 */
3937 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
3938 if (ret < 0) {
3939 wl1271_warning("build arp rsp failed: %d", ret);
3940 goto out;
3941 }
3942
3943 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
3944 (ACX_ARP_FILTER_ARP_FILTERING |
3945 ACX_ARP_FILTER_AUTO_ARP),
3946 addr);
3947 } else {
3948 wlvif->ip_addr = 0;
3949 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
3950 }
3951
3952 if (ret < 0)
3953 goto out;
3954 }
3955
Arik Nemtsove78a2872010-10-16 19:07:21 +02003956out:
3957 return;
3958}
3959
3960static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3961 struct ieee80211_vif *vif,
3962 struct ieee80211_bss_conf *bss_conf,
3963 u32 changed)
3964{
3965 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003966 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3967 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003968 int ret;
3969
3970 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3971 (int)changed);
3972
3973 mutex_lock(&wl->mutex);
3974
3975 if (unlikely(wl->state == WL1271_STATE_OFF))
3976 goto out;
3977
Eliad Peller10c8cd02011-10-10 10:13:06 +02003978 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3979 goto out;
3980
Ido Yariva6208652011-03-01 15:14:41 +02003981 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003982 if (ret < 0)
3983 goto out;
3984
3985 if (is_ap)
3986 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3987 else
3988 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3989
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003990 wl1271_ps_elp_sleep(wl);
3991
3992out:
3993 mutex_unlock(&wl->mutex);
3994}
3995
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003996static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3997 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003998 const struct ieee80211_tx_queue_params *params)
3999{
4000 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02004001 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02004002 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004003 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02004004
4005 mutex_lock(&wl->mutex);
4006
4007 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
4008
Kalle Valo4695dc92010-03-18 12:26:38 +02004009 if (params->uapsd)
4010 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
4011 else
4012 ps_scheme = CONF_PS_SCHEME_LEGACY;
4013
Eliad Peller5b37ddf2011-12-18 20:25:40 +02004014 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004015 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004016
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004017 ret = wl1271_ps_elp_wakeup(wl);
4018 if (ret < 0)
4019 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004020
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004021 /*
4022 * the txop is confed in units of 32us by the mac80211,
4023 * we need us
4024 */
Eliad Peller0603d892011-10-05 11:55:51 +02004025 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004026 params->cw_min, params->cw_max,
4027 params->aifs, params->txop << 5);
4028 if (ret < 0)
4029 goto out_sleep;
4030
Eliad Peller0603d892011-10-05 11:55:51 +02004031 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004032 CONF_CHANNEL_TYPE_EDCF,
4033 wl1271_tx_get_queue(queue),
4034 ps_scheme, CONF_ACK_POLICY_LEGACY,
4035 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004036
4037out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004038 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004039
4040out:
4041 mutex_unlock(&wl->mutex);
4042
4043 return ret;
4044}
4045
Eliad Peller37a41b42011-09-21 14:06:11 +03004046static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4047 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004048{
4049
4050 struct wl1271 *wl = hw->priv;
Eliad Peller9c531142012-01-31 11:57:18 +02004051 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004052 u64 mactime = ULLONG_MAX;
4053 int ret;
4054
4055 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4056
4057 mutex_lock(&wl->mutex);
4058
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004059 if (unlikely(wl->state == WL1271_STATE_OFF))
4060 goto out;
4061
Ido Yariva6208652011-03-01 15:14:41 +02004062 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004063 if (ret < 0)
4064 goto out;
4065
Eliad Peller9c531142012-01-31 11:57:18 +02004066 ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004067 if (ret < 0)
4068 goto out_sleep;
4069
4070out_sleep:
4071 wl1271_ps_elp_sleep(wl);
4072
4073out:
4074 mutex_unlock(&wl->mutex);
4075 return mactime;
4076}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004077
John W. Linvilleece550d2010-07-28 16:41:06 -04004078static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4079 struct survey_info *survey)
4080{
4081 struct wl1271 *wl = hw->priv;
4082 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004083
John W. Linvilleece550d2010-07-28 16:41:06 -04004084 if (idx != 0)
4085 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004086
John W. Linvilleece550d2010-07-28 16:41:06 -04004087 survey->channel = conf->channel;
4088 survey->filled = SURVEY_INFO_NOISE_DBM;
4089 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004090
John W. Linvilleece550d2010-07-28 16:41:06 -04004091 return 0;
4092}
4093
Arik Nemtsov409622e2011-02-23 00:22:29 +02004094static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004095 struct wl12xx_vif *wlvif,
4096 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004097{
4098 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004099 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004100
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004101
4102 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004103 wl1271_warning("could not allocate HLID - too much stations");
4104 return -EBUSY;
4105 }
4106
4107 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004108 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4109 if (ret < 0) {
4110 wl1271_warning("could not allocate HLID - too many links");
4111 return -EBUSY;
4112 }
4113
4114 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004115 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004116 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004117 return 0;
4118}
4119
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004120void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004121{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004122 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004123 return;
4124
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004125 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004126 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004127 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004128 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004129 __clear_bit(hlid, &wl->ap_ps_map);
4130 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004131 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004132 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004133}
4134
4135static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4136 struct ieee80211_vif *vif,
4137 struct ieee80211_sta *sta)
4138{
4139 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004140 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004141 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004142 int ret = 0;
4143 u8 hlid;
4144
4145 mutex_lock(&wl->mutex);
4146
4147 if (unlikely(wl->state == WL1271_STATE_OFF))
4148 goto out;
4149
Eliad Peller536129c2011-10-05 11:55:45 +02004150 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004151 goto out;
4152
4153 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4154
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004155 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004156 if (ret < 0)
4157 goto out;
4158
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004159 wl_sta = (struct wl1271_station *)sta->drv_priv;
4160 hlid = wl_sta->hlid;
4161
Ido Yariva6208652011-03-01 15:14:41 +02004162 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004163 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004164 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004165
Eliad Peller1b92f152011-10-10 10:13:09 +02004166 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004167 if (ret < 0)
4168 goto out_sleep;
4169
Eliad Pellerb67476e2011-08-14 13:17:23 +03004170 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4171 if (ret < 0)
4172 goto out_sleep;
4173
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004174 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4175 if (ret < 0)
4176 goto out_sleep;
4177
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004178out_sleep:
4179 wl1271_ps_elp_sleep(wl);
4180
Arik Nemtsov409622e2011-02-23 00:22:29 +02004181out_free_sta:
4182 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004183 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004184
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004185out:
4186 mutex_unlock(&wl->mutex);
4187 return ret;
4188}
4189
4190static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4191 struct ieee80211_vif *vif,
4192 struct ieee80211_sta *sta)
4193{
4194 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004195 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004196 struct wl1271_station *wl_sta;
4197 int ret = 0, id;
4198
4199 mutex_lock(&wl->mutex);
4200
4201 if (unlikely(wl->state == WL1271_STATE_OFF))
4202 goto out;
4203
Eliad Peller536129c2011-10-05 11:55:45 +02004204 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004205 goto out;
4206
4207 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4208
4209 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004210 id = wl_sta->hlid;
4211 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004212 goto out;
4213
Ido Yariva6208652011-03-01 15:14:41 +02004214 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004215 if (ret < 0)
4216 goto out;
4217
Eliad Pellerc690ec82011-08-14 13:17:07 +03004218 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004219 if (ret < 0)
4220 goto out_sleep;
4221
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004222 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004223
4224out_sleep:
4225 wl1271_ps_elp_sleep(wl);
4226
4227out:
4228 mutex_unlock(&wl->mutex);
4229 return ret;
4230}
4231
Luciano Coelho4623ec72011-03-21 19:26:41 +02004232static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4233 struct ieee80211_vif *vif,
4234 enum ieee80211_ampdu_mlme_action action,
4235 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4236 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004237{
4238 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004239 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004240 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004241 u8 hlid, *ba_bitmap;
4242
4243 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4244 tid);
4245
4246 /* sanity check - the fields in FW are only 8bits wide */
4247 if (WARN_ON(tid > 0xFF))
4248 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004249
4250 mutex_lock(&wl->mutex);
4251
4252 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4253 ret = -EAGAIN;
4254 goto out;
4255 }
4256
Eliad Peller536129c2011-10-05 11:55:45 +02004257 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004258 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004259 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004260 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004261 struct wl1271_station *wl_sta;
4262
4263 wl_sta = (struct wl1271_station *)sta->drv_priv;
4264 hlid = wl_sta->hlid;
4265 ba_bitmap = &wl->links[hlid].ba_bitmap;
4266 } else {
4267 ret = -EINVAL;
4268 goto out;
4269 }
4270
Ido Yariva6208652011-03-01 15:14:41 +02004271 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004272 if (ret < 0)
4273 goto out;
4274
Shahar Levi70559a02011-05-22 16:10:22 +03004275 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4276 tid, action);
4277
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004278 switch (action) {
4279 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004280 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004281 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004282 break;
4283 }
4284
4285 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4286 ret = -EBUSY;
4287 wl1271_error("exceeded max RX BA sessions");
4288 break;
4289 }
4290
4291 if (*ba_bitmap & BIT(tid)) {
4292 ret = -EINVAL;
4293 wl1271_error("cannot enable RX BA session on active "
4294 "tid: %d", tid);
4295 break;
4296 }
4297
4298 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4299 hlid);
4300 if (!ret) {
4301 *ba_bitmap |= BIT(tid);
4302 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004303 }
4304 break;
4305
4306 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004307 if (!(*ba_bitmap & BIT(tid))) {
4308 ret = -EINVAL;
4309 wl1271_error("no active RX BA session on tid: %d",
4310 tid);
4311 break;
4312 }
4313
4314 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4315 hlid);
4316 if (!ret) {
4317 *ba_bitmap &= ~BIT(tid);
4318 wl->ba_rx_session_count--;
4319 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004320 break;
4321
4322 /*
4323 * The BA initiator session management in FW independently.
4324 * Falling break here on purpose for all TX APDU commands.
4325 */
4326 case IEEE80211_AMPDU_TX_START:
4327 case IEEE80211_AMPDU_TX_STOP:
4328 case IEEE80211_AMPDU_TX_OPERATIONAL:
4329 ret = -EINVAL;
4330 break;
4331
4332 default:
4333 wl1271_error("Incorrect ampdu action id=%x\n", action);
4334 ret = -EINVAL;
4335 }
4336
4337 wl1271_ps_elp_sleep(wl);
4338
4339out:
4340 mutex_unlock(&wl->mutex);
4341
4342 return ret;
4343}
4344
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004345static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4346 struct ieee80211_vif *vif,
4347 const struct cfg80211_bitrate_mask *mask)
4348{
Eliad Peller83587502011-10-10 10:12:53 +02004349 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004350 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004351 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004352
4353 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4354 mask->control[NL80211_BAND_2GHZ].legacy,
4355 mask->control[NL80211_BAND_5GHZ].legacy);
4356
4357 mutex_lock(&wl->mutex);
4358
4359 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004360 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004361 wl1271_tx_enabled_rates_get(wl,
4362 mask->control[i].legacy,
4363 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004364
4365 if (unlikely(wl->state == WL1271_STATE_OFF))
4366 goto out;
4367
4368 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4369 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4370
4371 ret = wl1271_ps_elp_wakeup(wl);
4372 if (ret < 0)
4373 goto out;
4374
4375 wl1271_set_band_rate(wl, wlvif);
4376 wlvif->basic_rate =
4377 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4378 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4379
4380 wl1271_ps_elp_sleep(wl);
4381 }
4382out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004383 mutex_unlock(&wl->mutex);
4384
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004385 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004386}
4387
Shahar Levi6d158ff2011-09-08 13:01:33 +03004388static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4389 struct ieee80211_channel_switch *ch_switch)
4390{
4391 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004392 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004393 int ret;
4394
4395 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4396
4397 mutex_lock(&wl->mutex);
4398
4399 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004400 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4401 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4402 ieee80211_chswitch_done(vif, false);
4403 }
4404 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004405 }
4406
4407 ret = wl1271_ps_elp_wakeup(wl);
4408 if (ret < 0)
4409 goto out;
4410
Eliad Peller52630c52011-10-10 10:13:08 +02004411 /* TODO: change mac80211 to pass vif as param */
4412 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller8332f0f2012-01-31 11:57:19 +02004413 ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004414
Eliad Peller52630c52011-10-10 10:13:08 +02004415 if (!ret)
4416 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4417 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004418
4419 wl1271_ps_elp_sleep(wl);
4420
4421out:
4422 mutex_unlock(&wl->mutex);
4423}
4424
Arik Nemtsov33437892011-04-26 23:35:39 +03004425static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4426{
4427 struct wl1271 *wl = hw->priv;
4428 bool ret = false;
4429
4430 mutex_lock(&wl->mutex);
4431
4432 if (unlikely(wl->state == WL1271_STATE_OFF))
4433 goto out;
4434
4435 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004436 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004437out:
4438 mutex_unlock(&wl->mutex);
4439
4440 return ret;
4441}
4442
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004443/* can't be const, mac80211 writes to this */
4444static struct ieee80211_rate wl1271_rates[] = {
4445 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004446 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4447 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004448 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004449 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4450 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004451 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4452 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004453 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4454 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004455 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4456 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004457 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4458 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004459 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4460 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004461 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4462 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004463 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004464 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4465 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004466 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004467 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4468 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004469 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004470 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4471 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004472 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004473 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4474 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004475 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004476 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4477 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004478 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004479 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4480 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004481 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004482 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4483 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004484};
4485
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004486/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004487static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004488 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004489 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004490 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4491 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4492 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004493 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004494 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4495 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4496 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004497 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004498 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4499 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4500 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004501 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004502};
4503
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004504/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004505static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004506 /* MCS rates are used only with 11n */
Pontus Fuchsdefe02c2012-01-31 17:54:41 +02004507 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
Shahar Levi18357852010-10-13 16:09:41 +02004508 7, /* CONF_HW_RXTX_RATE_MCS7 */
4509 6, /* CONF_HW_RXTX_RATE_MCS6 */
4510 5, /* CONF_HW_RXTX_RATE_MCS5 */
4511 4, /* CONF_HW_RXTX_RATE_MCS4 */
4512 3, /* CONF_HW_RXTX_RATE_MCS3 */
4513 2, /* CONF_HW_RXTX_RATE_MCS2 */
4514 1, /* CONF_HW_RXTX_RATE_MCS1 */
4515 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004516
4517 11, /* CONF_HW_RXTX_RATE_54 */
4518 10, /* CONF_HW_RXTX_RATE_48 */
4519 9, /* CONF_HW_RXTX_RATE_36 */
4520 8, /* CONF_HW_RXTX_RATE_24 */
4521
4522 /* TI-specific rate */
4523 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4524
4525 7, /* CONF_HW_RXTX_RATE_18 */
4526 6, /* CONF_HW_RXTX_RATE_12 */
4527 3, /* CONF_HW_RXTX_RATE_11 */
4528 5, /* CONF_HW_RXTX_RATE_9 */
4529 4, /* CONF_HW_RXTX_RATE_6 */
4530 2, /* CONF_HW_RXTX_RATE_5_5 */
4531 1, /* CONF_HW_RXTX_RATE_2 */
4532 0 /* CONF_HW_RXTX_RATE_1 */
4533};
4534
Shahar Levie8b03a22010-10-13 16:09:39 +02004535/* 11n STA capabilities */
4536#define HW_RX_HIGHEST_RATE 72
4537
Shahar Levi00d20102010-11-08 11:20:10 +00004538#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004539 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4540 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004541 .ht_supported = true, \
4542 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4543 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4544 .mcs = { \
4545 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4546 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4547 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4548 }, \
4549}
4550
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004551/* can't be const, mac80211 writes to this */
4552static struct ieee80211_supported_band wl1271_band_2ghz = {
4553 .channels = wl1271_channels,
4554 .n_channels = ARRAY_SIZE(wl1271_channels),
4555 .bitrates = wl1271_rates,
4556 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004557 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004558};
4559
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004560/* 5 GHz data rates for WL1273 */
4561static struct ieee80211_rate wl1271_rates_5ghz[] = {
4562 { .bitrate = 60,
4563 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4564 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4565 { .bitrate = 90,
4566 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4567 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4568 { .bitrate = 120,
4569 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4570 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4571 { .bitrate = 180,
4572 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4573 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4574 { .bitrate = 240,
4575 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4576 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4577 { .bitrate = 360,
4578 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4579 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4580 { .bitrate = 480,
4581 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4582 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4583 { .bitrate = 540,
4584 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4585 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4586};
4587
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004588/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004589static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004590 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4591 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4592 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4593 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4594 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4595 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4596 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4597 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4598 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4599 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4600 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4601 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4602 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4603 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4604 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4605 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4606 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4607 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4608 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4609 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4610 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4611 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4612 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4613 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4614 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4615 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4616 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4617 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4618 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4619 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4620 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4621 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4622 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4623 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004624};
4625
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004626/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004627static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004628 /* MCS rates are used only with 11n */
Pontus Fuchsdefe02c2012-01-31 17:54:41 +02004629 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
Shahar Levi18357852010-10-13 16:09:41 +02004630 7, /* CONF_HW_RXTX_RATE_MCS7 */
4631 6, /* CONF_HW_RXTX_RATE_MCS6 */
4632 5, /* CONF_HW_RXTX_RATE_MCS5 */
4633 4, /* CONF_HW_RXTX_RATE_MCS4 */
4634 3, /* CONF_HW_RXTX_RATE_MCS3 */
4635 2, /* CONF_HW_RXTX_RATE_MCS2 */
4636 1, /* CONF_HW_RXTX_RATE_MCS1 */
4637 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004638
4639 7, /* CONF_HW_RXTX_RATE_54 */
4640 6, /* CONF_HW_RXTX_RATE_48 */
4641 5, /* CONF_HW_RXTX_RATE_36 */
4642 4, /* CONF_HW_RXTX_RATE_24 */
4643
4644 /* TI-specific rate */
4645 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4646
4647 3, /* CONF_HW_RXTX_RATE_18 */
4648 2, /* CONF_HW_RXTX_RATE_12 */
4649 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4650 1, /* CONF_HW_RXTX_RATE_9 */
4651 0, /* CONF_HW_RXTX_RATE_6 */
4652 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4653 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4654 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4655};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004656
4657static struct ieee80211_supported_band wl1271_band_5ghz = {
4658 .channels = wl1271_channels_5ghz,
4659 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4660 .bitrates = wl1271_rates_5ghz,
4661 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004662 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004663};
4664
Tobias Klausera0ea9492010-05-20 10:38:11 +02004665static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004666 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4667 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4668};
4669
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004670static const struct ieee80211_ops wl1271_ops = {
4671 .start = wl1271_op_start,
4672 .stop = wl1271_op_stop,
4673 .add_interface = wl1271_op_add_interface,
4674 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004675 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004676#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004677 .suspend = wl1271_op_suspend,
4678 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004679#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004680 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004681 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004682 .configure_filter = wl1271_op_configure_filter,
4683 .tx = wl1271_op_tx,
4684 .set_key = wl1271_op_set_key,
4685 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004686 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004687 .sched_scan_start = wl1271_op_sched_scan_start,
4688 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004689 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004690 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004691 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004692 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004693 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004694 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004695 .sta_add = wl1271_op_sta_add,
4696 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004697 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004698 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004699 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004700 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004701 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004702};
4703
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004704
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004705u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004706{
4707 u8 idx;
4708
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004709 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004710
4711 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4712 wl1271_error("Illegal RX rate from HW: %d", rate);
4713 return 0;
4714 }
4715
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004716 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004717 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4718 wl1271_error("Unsupported RX rate from HW: %d", rate);
4719 return 0;
4720 }
4721
4722 return idx;
4723}
4724
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004725static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4726 struct device_attribute *attr,
4727 char *buf)
4728{
4729 struct wl1271 *wl = dev_get_drvdata(dev);
4730 ssize_t len;
4731
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004732 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004733
4734 mutex_lock(&wl->mutex);
4735 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4736 wl->sg_enabled);
4737 mutex_unlock(&wl->mutex);
4738
4739 return len;
4740
4741}
4742
4743static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4744 struct device_attribute *attr,
4745 const char *buf, size_t count)
4746{
4747 struct wl1271 *wl = dev_get_drvdata(dev);
4748 unsigned long res;
4749 int ret;
4750
Luciano Coelho6277ed62011-04-01 17:49:54 +03004751 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004752 if (ret < 0) {
4753 wl1271_warning("incorrect value written to bt_coex_mode");
4754 return count;
4755 }
4756
4757 mutex_lock(&wl->mutex);
4758
4759 res = !!res;
4760
4761 if (res == wl->sg_enabled)
4762 goto out;
4763
4764 wl->sg_enabled = res;
4765
4766 if (wl->state == WL1271_STATE_OFF)
4767 goto out;
4768
Ido Yariva6208652011-03-01 15:14:41 +02004769 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004770 if (ret < 0)
4771 goto out;
4772
4773 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4774 wl1271_ps_elp_sleep(wl);
4775
4776 out:
4777 mutex_unlock(&wl->mutex);
4778 return count;
4779}
4780
4781static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4782 wl1271_sysfs_show_bt_coex_state,
4783 wl1271_sysfs_store_bt_coex_state);
4784
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004785static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4786 struct device_attribute *attr,
4787 char *buf)
4788{
4789 struct wl1271 *wl = dev_get_drvdata(dev);
4790 ssize_t len;
4791
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004792 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004793
4794 mutex_lock(&wl->mutex);
4795 if (wl->hw_pg_ver >= 0)
4796 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4797 else
4798 len = snprintf(buf, len, "n/a\n");
4799 mutex_unlock(&wl->mutex);
4800
4801 return len;
4802}
4803
Gery Kahn6f07b722011-07-18 14:21:49 +03004804static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004805 wl1271_sysfs_show_hw_pg_ver, NULL);
4806
Ido Yariv95dac04f2011-06-06 14:57:06 +03004807static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4808 struct bin_attribute *bin_attr,
4809 char *buffer, loff_t pos, size_t count)
4810{
4811 struct device *dev = container_of(kobj, struct device, kobj);
4812 struct wl1271 *wl = dev_get_drvdata(dev);
4813 ssize_t len;
4814 int ret;
4815
4816 ret = mutex_lock_interruptible(&wl->mutex);
4817 if (ret < 0)
4818 return -ERESTARTSYS;
4819
4820 /* Let only one thread read the log at a time, blocking others */
4821 while (wl->fwlog_size == 0) {
4822 DEFINE_WAIT(wait);
4823
4824 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4825 &wait,
4826 TASK_INTERRUPTIBLE);
4827
4828 if (wl->fwlog_size != 0) {
4829 finish_wait(&wl->fwlog_waitq, &wait);
4830 break;
4831 }
4832
4833 mutex_unlock(&wl->mutex);
4834
4835 schedule();
4836 finish_wait(&wl->fwlog_waitq, &wait);
4837
4838 if (signal_pending(current))
4839 return -ERESTARTSYS;
4840
4841 ret = mutex_lock_interruptible(&wl->mutex);
4842 if (ret < 0)
4843 return -ERESTARTSYS;
4844 }
4845
4846 /* Check if the fwlog is still valid */
4847 if (wl->fwlog_size < 0) {
4848 mutex_unlock(&wl->mutex);
4849 return 0;
4850 }
4851
4852 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4853 len = min(count, (size_t)wl->fwlog_size);
4854 wl->fwlog_size -= len;
4855 memcpy(buffer, wl->fwlog, len);
4856
4857 /* Make room for new messages */
4858 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4859
4860 mutex_unlock(&wl->mutex);
4861
4862 return len;
4863}
4864
4865static struct bin_attribute fwlog_attr = {
4866 .attr = {.name = "fwlog", .mode = S_IRUSR},
4867 .read = wl1271_sysfs_read_fwlog,
4868};
4869
Luciano Coelho5e037e72011-12-23 09:32:17 +02004870static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
4871{
4872 bool supported = false;
4873 u8 major, minor;
4874
4875 if (wl->chip.id == CHIP_ID_1283_PG20) {
4876 major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
4877 minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
4878
4879 /* in wl128x we have the MAC address if the PG is >= (2, 1) */
4880 if (major > 2 || (major == 2 && minor >= 1))
4881 supported = true;
4882 } else {
4883 major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
4884 minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
4885
4886 /* in wl127x we have the MAC address if the PG is >= (3, 1) */
4887 if (major == 3 && minor >= 1)
4888 supported = true;
4889 }
4890
4891 wl1271_debug(DEBUG_PROBE,
4892 "PG Ver major = %d minor = %d, MAC %s present",
4893 major, minor, supported ? "is" : "is not");
4894
4895 return supported;
4896}
4897
4898static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
4899 u32 oui, u32 nic, int n)
4900{
4901 int i;
4902
4903 wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
4904 oui, nic, n);
4905
4906 if (nic + n - 1 > 0xffffff)
4907 wl1271_warning("NIC part of the MAC address wraps around!");
4908
4909 for (i = 0; i < n; i++) {
4910 wl->addresses[i].addr[0] = (u8)(oui >> 16);
4911 wl->addresses[i].addr[1] = (u8)(oui >> 8);
4912 wl->addresses[i].addr[2] = (u8) oui;
4913 wl->addresses[i].addr[3] = (u8)(nic >> 16);
4914 wl->addresses[i].addr[4] = (u8)(nic >> 8);
4915 wl->addresses[i].addr[5] = (u8) nic;
4916 nic++;
4917 }
4918
4919 wl->hw->wiphy->n_addresses = n;
4920 wl->hw->wiphy->addresses = wl->addresses;
4921}
4922
4923static void wl12xx_get_fuse_mac(struct wl1271 *wl)
4924{
4925 u32 mac1, mac2;
4926
4927 wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
4928
4929 mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
4930 mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
4931
4932 /* these are the two parts of the BD_ADDR */
4933 wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
4934 ((mac1 & 0xff000000) >> 24);
4935 wl->fuse_nic_addr = mac1 & 0xffffff;
4936
4937 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
4938}
4939
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004940static int wl12xx_get_hw_info(struct wl1271 *wl)
4941{
4942 int ret;
4943 u32 die_info;
4944
4945 ret = wl12xx_set_power_on(wl);
4946 if (ret < 0)
4947 goto out;
4948
4949 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
4950
4951 if (wl->chip.id == CHIP_ID_1283_PG20)
4952 die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
4953 else
4954 die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
4955
4956 wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
4957
Luciano Coelho5e037e72011-12-23 09:32:17 +02004958 if (!wl12xx_mac_in_fuse(wl)) {
4959 wl->fuse_oui_addr = 0;
4960 wl->fuse_nic_addr = 0;
4961 } else {
4962 wl12xx_get_fuse_mac(wl);
4963 }
4964
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004965 wl1271_power_off(wl);
4966out:
4967 return ret;
4968}
4969
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004970static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004971{
4972 int ret;
Luciano Coelho5e037e72011-12-23 09:32:17 +02004973 u32 oui_addr = 0, nic_addr = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004974
4975 if (wl->mac80211_registered)
4976 return 0;
4977
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004978 ret = wl12xx_get_hw_info(wl);
4979 if (ret < 0) {
4980 wl1271_error("couldn't get hw info");
4981 goto out;
4982 }
4983
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004984 ret = wl1271_fetch_nvs(wl);
4985 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004986 /* NOTE: The wl->nvs->nvs element must be first, in
4987 * order to simplify the casting, we assume it is at
4988 * the beginning of the wl->nvs structure.
4989 */
4990 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004991
Luciano Coelho5e037e72011-12-23 09:32:17 +02004992 oui_addr =
4993 (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
4994 nic_addr =
4995 (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004996 }
4997
Luciano Coelho5e037e72011-12-23 09:32:17 +02004998 /* if the MAC address is zeroed in the NVS derive from fuse */
4999 if (oui_addr == 0 && nic_addr == 0) {
5000 oui_addr = wl->fuse_oui_addr;
5001 /* fuse has the BD_ADDR, the WLAN addresses are the next two */
5002 nic_addr = wl->fuse_nic_addr + 1;
5003 }
5004
5005 wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005006
5007 ret = ieee80211_register_hw(wl->hw);
5008 if (ret < 0) {
5009 wl1271_error("unable to register mac80211 hw: %d", ret);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005010 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005011 }
5012
5013 wl->mac80211_registered = true;
5014
Eliad Pellerd60080a2010-11-24 12:53:16 +02005015 wl1271_debugfs_init(wl);
5016
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03005017 register_netdevice_notifier(&wl1271_dev_notifier);
5018
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005019 wl1271_notice("loaded");
5020
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005021out:
5022 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005023}
5024
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005025static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005026{
Eliad Peller3fcdab72012-02-06 12:47:54 +02005027 if (wl->plt)
Ido Yarivf3df1332012-01-11 09:42:39 +02005028 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01005029
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03005030 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005031 ieee80211_unregister_hw(wl->hw);
5032 wl->mac80211_registered = false;
5033
5034}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005035
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005036static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005037{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005038 static const u32 cipher_suites[] = {
5039 WLAN_CIPHER_SUITE_WEP40,
5040 WLAN_CIPHER_SUITE_WEP104,
5041 WLAN_CIPHER_SUITE_TKIP,
5042 WLAN_CIPHER_SUITE_CCMP,
5043 WL1271_CIPHER_SUITE_GEM,
5044 };
5045
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03005046 /* The tx descriptor buffer and the TKIP space. */
Eliad Peller5ec8a442012-02-02 12:22:09 +02005047 wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03005048 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005049
5050 /* unit us */
5051 /* FIXME: find a proper value */
5052 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03005053 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005054
5055 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02005056 IEEE80211_HW_SUPPORTS_PS |
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02005057 IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02005058 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02005059 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03005060 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03005061 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03005062 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03005063 IEEE80211_HW_AP_LINK_PS |
5064 IEEE80211_HW_AMPDU_AGGREGATION |
Eliad Peller79aba1b2012-02-02 13:15:35 +02005065 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
5066 IEEE80211_HW_SCAN_WHILE_IDLE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005067
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005068 wl->hw->wiphy->cipher_suites = cipher_suites;
5069 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
5070
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02005071 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03005072 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
5073 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005074 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03005075 wl->hw->wiphy->max_sched_scan_ssids = 16;
5076 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02005077 /*
5078 * Maximum length of elements in scanning probe request templates
5079 * should be the maximum length possible for a template, without
5080 * the IEEE80211 header of the template
5081 */
Ido Reisc08e3712012-02-02 13:54:27 +02005082 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02005083 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005084
Ido Reisc08e3712012-02-02 13:54:27 +02005085 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03005086 sizeof(struct ieee80211_header);
5087
Eliad Peller1ec23f72011-08-25 14:26:54 +03005088 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
5089
Luciano Coelho4a31c112011-03-21 23:16:14 +02005090 /* make sure all our channels fit in the scanned_ch bitmask */
5091 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
5092 ARRAY_SIZE(wl1271_channels_5ghz) >
5093 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005094 /*
5095 * We keep local copies of the band structs because we need to
5096 * modify them on a per-device basis.
5097 */
5098 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
5099 sizeof(wl1271_band_2ghz));
5100 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
5101 sizeof(wl1271_band_5ghz));
5102
5103 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
5104 &wl->bands[IEEE80211_BAND_2GHZ];
5105 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
5106 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005107
Kalle Valo12bd8942010-03-18 12:26:33 +02005108 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02005109 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02005110
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01005111 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
5112
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02005113 /* the FW answers probe-requests in AP-mode */
5114 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
5115 wl->hw->wiphy->probe_resp_offload =
5116 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
5117 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
5118 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
5119
Felipe Balbia390e852011-10-06 10:07:44 +03005120 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005121
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005122 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02005123 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005124
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005125 wl->hw->max_rx_aggregation_subframes = 8;
5126
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005127 return 0;
5128}
5129
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005130#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005131
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005132static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005133{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005134 struct ieee80211_hw *hw;
5135 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005136 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005137 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005138
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005139 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005140
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005141 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5142 if (!hw) {
5143 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005144 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005145 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005146 }
5147
5148 wl = hw->priv;
5149 memset(wl, 0, sizeof(*wl));
5150
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005151 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005152 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005153
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005154 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005155
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005156 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005157 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005158 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5159
Ido Yariva6208652011-03-01 15:14:41 +02005160 skb_queue_head_init(&wl->deferred_rx_queue);
5161 skb_queue_head_init(&wl->deferred_tx_queue);
5162
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005163 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005164 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005165 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5166 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5167 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005168
Eliad Peller92ef8962011-06-07 12:50:46 +03005169 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5170 if (!wl->freezable_wq) {
5171 ret = -ENOMEM;
5172 goto err_hw;
5173 }
5174
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005175 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005176 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005177 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005178 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005179 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005180 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005181 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005182 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005183 wl->ap_ps_map = 0;
5184 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005185 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005186 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005187 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005188 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005189 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005190 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005191 wl->fwlog_size = 0;
5192 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005193
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005194 /* The system link is always allocated */
5195 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5196
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005197 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005198 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005199 wl->tx_frames[i] = NULL;
5200
5201 spin_lock_init(&wl->wl_lock);
5202
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005203 wl->state = WL1271_STATE_OFF;
Eliad Peller3fcdab72012-02-06 12:47:54 +02005204 wl->fw_type = WL12XX_FW_TYPE_NONE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005205 mutex_init(&wl->mutex);
5206
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005207 /* Apply default driver configuration. */
5208 wl1271_conf_init(wl);
5209
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005210 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5211 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5212 if (!wl->aggr_buf) {
5213 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005214 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005215 }
5216
Ido Yariv990f5de2011-03-31 10:06:59 +02005217 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5218 if (!wl->dummy_packet) {
5219 ret = -ENOMEM;
5220 goto err_aggr;
5221 }
5222
Ido Yariv95dac04f2011-06-06 14:57:06 +03005223 /* Allocate one page for the FW log */
5224 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5225 if (!wl->fwlog) {
5226 ret = -ENOMEM;
5227 goto err_dummy_packet;
5228 }
5229
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005230 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005231
Ido Yariv990f5de2011-03-31 10:06:59 +02005232err_dummy_packet:
5233 dev_kfree_skb(wl->dummy_packet);
5234
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005235err_aggr:
5236 free_pages((unsigned long)wl->aggr_buf, order);
5237
Eliad Peller92ef8962011-06-07 12:50:46 +03005238err_wq:
5239 destroy_workqueue(wl->freezable_wq);
5240
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005241err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005242 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005243 ieee80211_free_hw(hw);
5244
5245err_hw_alloc:
5246
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005247 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005248}
5249
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005250static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005251{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005252 /* Unblock any fwlog readers */
5253 mutex_lock(&wl->mutex);
5254 wl->fwlog_size = -1;
5255 wake_up_interruptible_all(&wl->fwlog_waitq);
5256 mutex_unlock(&wl->mutex);
5257
Felipe Balbif79f8902011-10-06 13:05:25 +03005258 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005259
Felipe Balbif79f8902011-10-06 13:05:25 +03005260 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005261
Felipe Balbif79f8902011-10-06 13:05:25 +03005262 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005263 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005264 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005265 free_pages((unsigned long)wl->aggr_buf,
5266 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005267
5268 wl1271_debugfs_exit(wl);
5269
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005270 vfree(wl->fw);
5271 wl->fw = NULL;
Eliad Peller3fcdab72012-02-06 12:47:54 +02005272 wl->fw_type = WL12XX_FW_TYPE_NONE;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005273 kfree(wl->nvs);
5274 wl->nvs = NULL;
5275
5276 kfree(wl->fw_status);
5277 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005278 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005279
5280 ieee80211_free_hw(wl->hw);
5281
5282 return 0;
5283}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005284
Felipe Balbia390e852011-10-06 10:07:44 +03005285static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5286{
5287 struct wl1271 *wl = cookie;
5288 unsigned long flags;
5289
5290 wl1271_debug(DEBUG_IRQ, "IRQ");
5291
5292 /* complete the ELP completion */
5293 spin_lock_irqsave(&wl->wl_lock, flags);
5294 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5295 if (wl->elp_compl) {
5296 complete(wl->elp_compl);
5297 wl->elp_compl = NULL;
5298 }
5299
5300 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5301 /* don't enqueue a work right now. mark it as pending */
5302 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5303 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5304 disable_irq_nosync(wl->irq);
5305 pm_wakeup_event(wl->dev, 0);
5306 spin_unlock_irqrestore(&wl->wl_lock, flags);
5307 return IRQ_HANDLED;
5308 }
5309 spin_unlock_irqrestore(&wl->wl_lock, flags);
5310
5311 return IRQ_WAKE_THREAD;
5312}
5313
Felipe Balbice2a2172011-10-05 14:12:55 +03005314static int __devinit wl12xx_probe(struct platform_device *pdev)
5315{
Felipe Balbia390e852011-10-06 10:07:44 +03005316 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5317 struct ieee80211_hw *hw;
5318 struct wl1271 *wl;
5319 unsigned long irqflags;
5320 int ret = -ENODEV;
5321
5322 hw = wl1271_alloc_hw();
5323 if (IS_ERR(hw)) {
5324 wl1271_error("can't allocate hw");
5325 ret = PTR_ERR(hw);
5326 goto out;
5327 }
5328
5329 wl = hw->priv;
5330 wl->irq = platform_get_irq(pdev, 0);
5331 wl->ref_clock = pdata->board_ref_clock;
5332 wl->tcxo_clock = pdata->board_tcxo_clock;
5333 wl->platform_quirks = pdata->platform_quirks;
5334 wl->set_power = pdata->set_power;
5335 wl->dev = &pdev->dev;
5336 wl->if_ops = pdata->ops;
5337
5338 platform_set_drvdata(pdev, wl);
5339
5340 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5341 irqflags = IRQF_TRIGGER_RISING;
5342 else
5343 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5344
5345 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5346 irqflags,
5347 pdev->name, wl);
5348 if (ret < 0) {
5349 wl1271_error("request_irq() failed: %d", ret);
5350 goto out_free_hw;
5351 }
5352
5353 ret = enable_irq_wake(wl->irq);
5354 if (!ret) {
5355 wl->irq_wake_enabled = true;
5356 device_init_wakeup(wl->dev, 1);
5357 if (pdata->pwr_in_suspend)
5358 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5359
5360 }
5361 disable_irq(wl->irq);
5362
5363 ret = wl1271_init_ieee80211(wl);
5364 if (ret)
5365 goto out_irq;
5366
5367 ret = wl1271_register_hw(wl);
5368 if (ret)
5369 goto out_irq;
5370
Felipe Balbif79f8902011-10-06 13:05:25 +03005371 /* Create sysfs file to control bt coex state */
5372 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5373 if (ret < 0) {
5374 wl1271_error("failed to create sysfs file bt_coex_state");
5375 goto out_irq;
5376 }
5377
5378 /* Create sysfs file to get HW PG version */
5379 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5380 if (ret < 0) {
5381 wl1271_error("failed to create sysfs file hw_pg_ver");
5382 goto out_bt_coex_state;
5383 }
5384
5385 /* Create sysfs file for the FW log */
5386 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5387 if (ret < 0) {
5388 wl1271_error("failed to create sysfs file fwlog");
5389 goto out_hw_pg_ver;
5390 }
5391
Felipe Balbice2a2172011-10-05 14:12:55 +03005392 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005393
Felipe Balbif79f8902011-10-06 13:05:25 +03005394out_hw_pg_ver:
5395 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5396
5397out_bt_coex_state:
5398 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5399
Felipe Balbia390e852011-10-06 10:07:44 +03005400out_irq:
5401 free_irq(wl->irq, wl);
5402
5403out_free_hw:
5404 wl1271_free_hw(wl);
5405
5406out:
5407 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005408}
5409
5410static int __devexit wl12xx_remove(struct platform_device *pdev)
5411{
Felipe Balbia390e852011-10-06 10:07:44 +03005412 struct wl1271 *wl = platform_get_drvdata(pdev);
5413
5414 if (wl->irq_wake_enabled) {
5415 device_init_wakeup(wl->dev, 0);
5416 disable_irq_wake(wl->irq);
5417 }
5418 wl1271_unregister_hw(wl);
5419 free_irq(wl->irq, wl);
5420 wl1271_free_hw(wl);
5421
Felipe Balbice2a2172011-10-05 14:12:55 +03005422 return 0;
5423}
5424
5425static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005426 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005427 { } /* Terminating Entry */
5428};
5429MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5430
5431static struct platform_driver wl12xx_driver = {
5432 .probe = wl12xx_probe,
5433 .remove = __devexit_p(wl12xx_remove),
5434 .id_table = wl12xx_id_table,
5435 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005436 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005437 .owner = THIS_MODULE,
5438 }
5439};
5440
5441static int __init wl12xx_init(void)
5442{
5443 return platform_driver_register(&wl12xx_driver);
5444}
5445module_init(wl12xx_init);
5446
5447static void __exit wl12xx_exit(void)
5448{
5449 platform_driver_unregister(&wl12xx_driver);
5450}
5451module_exit(wl12xx_exit);
5452
Guy Eilam491bbd62011-01-12 10:33:29 +01005453u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005454EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005455module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005456MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5457
Ido Yariv95dac04f2011-06-06 14:57:06 +03005458module_param_named(fwlog, fwlog_param, charp, 0);
Luciano Coelho2c882fa2012-02-07 12:37:33 +02005459MODULE_PARM_DESC(fwlog,
Ido Yariv95dac04f2011-06-06 14:57:06 +03005460 "FW logger options: continuous, ondemand, dbgpins or disable");
5461
Eliad Peller2a5bff02011-08-25 18:10:59 +03005462module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5463MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5464
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005465MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005466MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005467MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");