blob: b3d4ef5b900de1d3d049a6d7f469803e9df7caa2 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000038#include "reg.h"
39#include "io.h"
40#include "event.h"
41#include "tx.h"
42#include "rx.h"
43#include "ps.h"
44#include "init.h"
45#include "debugfs.h"
46#include "cmd.h"
47#include "boot.h"
48#include "testmode.h"
49#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030050
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020051#define WL1271_BOOT_RETRIES 3
52
Juuso Oikarinen8a080482009-10-13 12:47:44 +030053static struct conf_drv_settings default_conf = {
54 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030055 .params = {
56 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
57 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
58 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
61 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
62 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
64 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
65 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
66 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
68 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
69 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
70 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
71 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
73 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
74 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
75 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
76 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
77 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
78 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
79 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
82 /* active scan params */
83 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
84 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
85 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
86 /* passive scan params */
87 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
88 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
90 /* passive scan in dual antenna params */
91 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
92 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
93 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
94 /* general params */
95 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
96 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
97 [CONF_SG_BEACON_MISS_PERCENT] = 60,
98 [CONF_SG_DHCP_TIME] = 5000,
99 [CONF_SG_RXT] = 1200,
100 [CONF_SG_TXT] = 1000,
101 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
102 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
103 [CONF_SG_HV3_MAX_SERVED] = 6,
104 [CONF_SG_PS_POLL_TIMEOUT] = 10,
105 [CONF_SG_UPSD_TIMEOUT] = 10,
106 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
107 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
108 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
109 /* AP params */
110 [CONF_AP_BEACON_MISS_TX] = 3,
111 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
112 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
113 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
114 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
115 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300116 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200117 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300118 },
119 .rx = {
120 .rx_msdu_life_time = 512000,
121 .packet_detection_threshold = 0,
122 .ps_poll_timeout = 15,
123 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300124 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200125 .rx_cca_threshold = 0,
126 .irq_blk_threshold = 0xFFFF,
127 .irq_pkt_threshold = 0,
128 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300129 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
130 },
131 .tx = {
132 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200133 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300134 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .short_retry_limit = 10,
136 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200137 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300138 },
139 .ac_conf_count = 4,
140 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_BE,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = 3,
146 .tx_op_limit = 0,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_BK,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = 7,
153 .tx_op_limit = 0,
154 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200155 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300156 .ac = CONF_TX_AC_VI,
157 .cw_min = 15,
158 .cw_max = 63,
159 .aifsn = CONF_TX_AIFS_PIFS,
160 .tx_op_limit = 3008,
161 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200162 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300163 .ac = CONF_TX_AC_VO,
164 .cw_min = 15,
165 .cw_max = 63,
166 .aifsn = CONF_TX_AIFS_PIFS,
167 .tx_op_limit = 1504,
168 },
169 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300170 .max_tx_retries = 100,
171 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200172 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300173 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 [CONF_TX_AC_BE] = {
175 .queue_id = CONF_TX_AC_BE,
176 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .tsid = CONF_TX_AC_BE,
178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200182 [CONF_TX_AC_BK] = {
183 .queue_id = CONF_TX_AC_BK,
184 .channel_type = CONF_CHANNEL_TYPE_EDCF,
185 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_VI] = {
191 .queue_id = CONF_TX_AC_VI,
192 .channel_type = CONF_CHANNEL_TYPE_EDCF,
193 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300194 .ps_scheme = CONF_PS_SCHEME_LEGACY,
195 .ack_policy = CONF_ACK_POLICY_LEGACY,
196 .apsd_conf = {0, 0},
197 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200198 [CONF_TX_AC_VO] = {
199 .queue_id = CONF_TX_AC_VO,
200 .channel_type = CONF_CHANNEL_TYPE_EDCF,
201 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300202 .ps_scheme = CONF_PS_SCHEME_LEGACY,
203 .ack_policy = CONF_ACK_POLICY_LEGACY,
204 .apsd_conf = {0, 0},
205 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300206 },
207 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200208 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300209 .tx_compl_threshold = 4,
210 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
211 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200212 .tmpl_short_retry_limit = 10,
213 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300214 },
215 .conn = {
216 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300217 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300219 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_ie = {
221 [0] = {
222 .ie = WLAN_EID_CHANNEL_SWITCH,
223 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300224 },
225 [1] = {
226 .ie = WLAN_EID_HT_INFORMATION,
227 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200230 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 .bss_lose_timeout = 100,
232 .beacon_rx_timeout = 10000,
233 .broadcast_timeout = 20000,
234 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300235 .ps_poll_threshold = 10,
236 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300237 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e02011-03-14 18:53:10 +0200238 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300239 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300240 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200241 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300242 .keep_alive_interval = 55000,
243 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300244 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200245 .itrim = {
246 .enable = false,
247 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200248 },
249 .pm_config = {
250 .host_clk_settling_time = 5000,
251 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300252 },
253 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 .trigger_pacing = 1,
255 .avg_weight_rssi_beacon = 20,
256 .avg_weight_rssi_data = 10,
257 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100258 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200259 },
260 .scan = {
261 .min_dwell_time_active = 7500,
262 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100263 .min_dwell_time_passive = 100000,
264 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200265 .num_probe_reqs = 2,
266 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300267 .sched_scan = {
268 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300269 .min_dwell_time_active = 30,
270 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300271 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300272 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .num_probe_reqs = 2,
274 .rssi_threshold = -90,
275 .snr_threshold = 0,
276 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200277 .rf = {
278 .tx_per_channel_power_compensation_2 = {
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280 },
281 .tx_per_channel_power_compensation_5 = {
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 },
286 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100287 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300288 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .tx_ba_win_size = 64,
290 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300291 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100292 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200293 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200294 .num_stations = 1,
295 .ssid_profiles = 1,
296 .rx_block_num = 70,
297 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300298 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200299 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200300 .min_req_rx_blocks = 22,
301 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200302 },
303 .mem_wl128x = {
304 .num_stations = 1,
305 .ssid_profiles = 1,
306 .rx_block_num = 40,
307 .tx_min_block_num = 40,
308 .dynamic_memory = 1,
309 .min_req_tx_blocks = 45,
310 .min_req_rx_blocks = 22,
311 .tx_min = 27,
312 },
Shahar Leviff868432011-04-11 15:41:46 +0300313 .fm_coex = {
314 .enable = true,
315 .swallow_period = 5,
316 .n_divider_fref_set_1 = 0xff, /* default */
317 .n_divider_fref_set_2 = 12,
318 .m_divider_fref_set_1 = 148,
319 .m_divider_fref_set_2 = 0xffff, /* default */
320 .coex_pll_stabilization_time = 0xffffffff, /* default */
321 .ldo_stabilization_time = 0xffff, /* default */
322 .fm_disturbed_band_margin = 0xff, /* default */
323 .swallow_clk_diff = 0xff, /* default */
324 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300325 .rx_streaming = {
326 .duration = 150,
327 .queues = 0x1,
328 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300329 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300330 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300331 .fwlog = {
332 .mode = WL12XX_FWLOG_ON_DEMAND,
333 .mem_blocks = 2,
334 .severity = 0,
335 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
336 .output = WL12XX_FWLOG_OUTPUT_HOST,
337 .threshold = 0,
338 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300339 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300340 .rate = {
341 .rate_retry_score = 32000,
342 .per_add = 8192,
343 .per_th1 = 2048,
344 .per_th2 = 4096,
345 .max_per = 8100,
346 .inverse_curiosity_factor = 5,
347 .tx_fail_low_th = 4,
348 .tx_fail_high_th = 10,
349 .per_alpha_shift = 4,
350 .per_add_shift = 13,
351 .per_beta1_shift = 10,
352 .per_beta2_shift = 8,
353 .rate_check_up = 2,
354 .rate_check_down = 12,
355 .rate_retry_policy = {
356 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00,
359 },
360 },
Eliad Peller94877752011-08-28 15:11:56 +0300361 .hangover = {
362 .recover_time = 0,
363 .hangover_period = 20,
364 .dynamic_mode = 1,
365 .early_termination_mode = 1,
366 .max_period = 20,
367 .min_period = 1,
368 .increase_delta = 1,
369 .decrease_delta = 2,
370 .quiet_time = 4,
371 .increase_time = 1,
372 .window_size = 16,
373 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300374};
375
Ido Yariv95dac04f2011-06-06 14:57:06 +0300376static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300377static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300379static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200380 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300381 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200382static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200383
384
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200385static void wl1271_device_release(struct device *dev)
386{
387
388}
389
390static struct platform_device wl1271_device = {
391 .name = "wl1271",
392 .id = -1,
393
394 /* device model insists to have a release function */
395 .dev = {
396 .release = wl1271_device_release,
397 },
398};
399
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200400static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300401static LIST_HEAD(wl_list);
402
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300403static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
404{
Eliad Peller0603d892011-10-05 11:55:51 +0200405 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
406 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300407 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200408
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300409 if (operstate != IF_OPER_UP)
410 return 0;
411
412 if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
413 return 0;
414
Eliad Pellerb67476e2011-08-14 13:17:23 +0300415 ret = wl12xx_cmd_set_peer_state(wl, wl->sta_hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300416 if (ret < 0)
417 return ret;
418
Eliad Peller0603d892011-10-05 11:55:51 +0200419 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300420
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300421 wl1271_info("Association completed.");
422 return 0;
423}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300424static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
425 void *arg)
426{
427 struct net_device *dev = arg;
428 struct wireless_dev *wdev;
429 struct wiphy *wiphy;
430 struct ieee80211_hw *hw;
431 struct wl1271 *wl;
432 struct wl1271 *wl_temp;
433 int ret = 0;
434
435 /* Check that this notification is for us. */
436 if (what != NETDEV_CHANGE)
437 return NOTIFY_DONE;
438
439 wdev = dev->ieee80211_ptr;
440 if (wdev == NULL)
441 return NOTIFY_DONE;
442
443 wiphy = wdev->wiphy;
444 if (wiphy == NULL)
445 return NOTIFY_DONE;
446
447 hw = wiphy_priv(wiphy);
448 if (hw == NULL)
449 return NOTIFY_DONE;
450
451 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200452 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300453 list_for_each_entry(wl, &wl_list, list) {
454 if (wl == wl_temp)
455 break;
456 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200457 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300458 if (wl != wl_temp)
459 return NOTIFY_DONE;
460
461 mutex_lock(&wl->mutex);
462
463 if (wl->state == WL1271_STATE_OFF)
464 goto out;
465
466 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
467 goto out;
468
Ido Yariva6208652011-03-01 15:14:41 +0200469 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300470 if (ret < 0)
471 goto out;
472
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300473 wl1271_check_operstate(wl, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300474
475 wl1271_ps_elp_sleep(wl);
476
477out:
478 mutex_unlock(&wl->mutex);
479
480 return NOTIFY_OK;
481}
482
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100483static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200484 struct regulatory_request *request)
485{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100486 struct ieee80211_supported_band *band;
487 struct ieee80211_channel *ch;
488 int i;
489
490 band = wiphy->bands[IEEE80211_BAND_5GHZ];
491 for (i = 0; i < band->n_channels; i++) {
492 ch = &band->channels[i];
493 if (ch->flags & IEEE80211_CHAN_DISABLED)
494 continue;
495
496 if (ch->flags & IEEE80211_CHAN_RADAR)
497 ch->flags |= IEEE80211_CHAN_NO_IBSS |
498 IEEE80211_CHAN_PASSIVE_SCAN;
499
500 }
501
502 return 0;
503}
504
Eliad Peller77ddaa12011-05-15 11:10:29 +0300505static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
506{
507 int ret = 0;
508
509 /* we should hold wl->mutex */
510 ret = wl1271_acx_ps_rx_streaming(wl, enable);
511 if (ret < 0)
512 goto out;
513
514 if (enable)
515 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
516 else
517 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
518out:
519 return ret;
520}
521
522/*
523 * this function is being called when the rx_streaming interval
524 * has beed changed or rx_streaming should be disabled
525 */
526int wl1271_recalc_rx_streaming(struct wl1271 *wl)
527{
528 int ret = 0;
529 int period = wl->conf.rx_streaming.interval;
530
531 /* don't reconfigure if rx_streaming is disabled */
532 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
533 goto out;
534
535 /* reconfigure/disable according to new streaming_period */
536 if (period &&
537 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
538 (wl->conf.rx_streaming.always ||
539 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
540 ret = wl1271_set_rx_streaming(wl, true);
541 else {
542 ret = wl1271_set_rx_streaming(wl, false);
543 /* don't cancel_work_sync since we might deadlock */
544 del_timer_sync(&wl->rx_streaming_timer);
545 }
546out:
547 return ret;
548}
549
550static void wl1271_rx_streaming_enable_work(struct work_struct *work)
551{
552 int ret;
553 struct wl1271 *wl =
554 container_of(work, struct wl1271, rx_streaming_enable_work);
555
556 mutex_lock(&wl->mutex);
557
558 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
559 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
560 (!wl->conf.rx_streaming.always &&
561 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
562 goto out;
563
564 if (!wl->conf.rx_streaming.interval)
565 goto out;
566
567 ret = wl1271_ps_elp_wakeup(wl);
568 if (ret < 0)
569 goto out;
570
571 ret = wl1271_set_rx_streaming(wl, true);
572 if (ret < 0)
573 goto out_sleep;
574
575 /* stop it after some time of inactivity */
576 mod_timer(&wl->rx_streaming_timer,
577 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
578
579out_sleep:
580 wl1271_ps_elp_sleep(wl);
581out:
582 mutex_unlock(&wl->mutex);
583}
584
585static void wl1271_rx_streaming_disable_work(struct work_struct *work)
586{
587 int ret;
588 struct wl1271 *wl =
589 container_of(work, struct wl1271, rx_streaming_disable_work);
590
591 mutex_lock(&wl->mutex);
592
593 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
594 goto out;
595
596 ret = wl1271_ps_elp_wakeup(wl);
597 if (ret < 0)
598 goto out;
599
600 ret = wl1271_set_rx_streaming(wl, false);
601 if (ret)
602 goto out_sleep;
603
604out_sleep:
605 wl1271_ps_elp_sleep(wl);
606out:
607 mutex_unlock(&wl->mutex);
608}
609
610static void wl1271_rx_streaming_timer(unsigned long data)
611{
612 struct wl1271 *wl = (struct wl1271 *)data;
613 ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
614}
615
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300616static void wl1271_conf_init(struct wl1271 *wl)
617{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300618
619 /*
620 * This function applies the default configuration to the driver. This
621 * function is invoked upon driver load (spi probe.)
622 *
623 * The configuration is stored in a run-time structure in order to
624 * facilitate for run-time adjustment of any of the parameters. Making
625 * changes to the configuration structure will apply the new values on
626 * the next interface up (wl1271_op_start.)
627 */
628
629 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300630 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300631
Ido Yariv95dac04f2011-06-06 14:57:06 +0300632 /* Adjust settings according to optional module parameters */
633 if (fwlog_param) {
634 if (!strcmp(fwlog_param, "continuous")) {
635 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
636 } else if (!strcmp(fwlog_param, "ondemand")) {
637 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
638 } else if (!strcmp(fwlog_param, "dbgpins")) {
639 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
640 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
641 } else if (!strcmp(fwlog_param, "disable")) {
642 wl->conf.fwlog.mem_blocks = 0;
643 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
644 } else {
645 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
646 }
647 }
648}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300649
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300650static int wl1271_plt_init(struct wl1271 *wl)
651{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200652 struct conf_tx_ac_category *conf_ac;
653 struct conf_tx_tid *conf_tid;
654 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300655
Shahar Levi49d750ca2011-03-06 16:32:09 +0200656 if (wl->chip.id == CHIP_ID_1283_PG20)
657 ret = wl128x_cmd_general_parms(wl);
658 else
659 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200660 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200661 return ret;
662
Shahar Levi49d750ca2011-03-06 16:32:09 +0200663 if (wl->chip.id == CHIP_ID_1283_PG20)
664 ret = wl128x_cmd_radio_parms(wl);
665 else
666 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200667 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200668 return ret;
669
Shahar Levi49d750ca2011-03-06 16:32:09 +0200670 if (wl->chip.id != CHIP_ID_1283_PG20) {
671 ret = wl1271_cmd_ext_radio_parms(wl);
672 if (ret < 0)
673 return ret;
674 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200675 if (ret < 0)
676 return ret;
677
Shahar Levi48a61472011-03-06 16:32:08 +0200678 /* Chip-specific initializations */
679 ret = wl1271_chip_specific_init(wl);
680 if (ret < 0)
681 return ret;
682
Eliad Peller92c77c72011-10-05 11:55:40 +0200683 ret = wl1271_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200684 if (ret < 0)
685 return ret;
686
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300687 ret = wl1271_acx_init_mem_config(wl);
688 if (ret < 0)
689 return ret;
690
Luciano Coelho12419cc2010-02-18 13:25:44 +0200691 /* PHY layer config */
692 ret = wl1271_init_phy_config(wl);
693 if (ret < 0)
694 goto out_free_memmap;
695
696 ret = wl1271_acx_dco_itrim_params(wl);
697 if (ret < 0)
698 goto out_free_memmap;
699
700 /* Initialize connection monitoring thresholds */
Eliad Peller0603d892011-10-05 11:55:51 +0200701 ret = wl1271_acx_conn_monit_params(wl, NULL, false); /* TODO: fix */
Luciano Coelho12419cc2010-02-18 13:25:44 +0200702 if (ret < 0)
703 goto out_free_memmap;
704
705 /* Bluetooth WLAN coexistence */
706 ret = wl1271_init_pta(wl);
707 if (ret < 0)
708 goto out_free_memmap;
709
Shahar Leviff868432011-04-11 15:41:46 +0300710 /* FM WLAN coexistence */
711 ret = wl1271_acx_fm_coex(wl);
712 if (ret < 0)
713 goto out_free_memmap;
714
Luciano Coelho12419cc2010-02-18 13:25:44 +0200715 /* Energy detection */
716 ret = wl1271_init_energy_detection(wl);
717 if (ret < 0)
718 goto out_free_memmap;
719
Eliad Peller7f0979882011-08-14 13:17:06 +0300720 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600721 if (ret < 0)
722 goto out_free_memmap;
723
Luciano Coelho12419cc2010-02-18 13:25:44 +0200724 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100725 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200726 if (ret < 0)
727 goto out_free_memmap;
728
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200729 /* Default TID/AC configuration */
730 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200731 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200732 conf_ac = &wl->conf.tx.ac_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200733 /* TODO: fix */
734 ret = wl1271_acx_ac_cfg(wl, NULL, conf_ac->ac, conf_ac->cw_min,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200735 conf_ac->cw_max, conf_ac->aifsn,
736 conf_ac->tx_op_limit);
737 if (ret < 0)
738 goto out_free_memmap;
739
Luciano Coelho12419cc2010-02-18 13:25:44 +0200740 conf_tid = &wl->conf.tx.tid_conf[i];
Eliad Peller0603d892011-10-05 11:55:51 +0200741 /* TODO: fix */
742 ret = wl1271_acx_tid_cfg(wl, NULL, conf_tid->queue_id,
Luciano Coelho12419cc2010-02-18 13:25:44 +0200743 conf_tid->channel_type,
744 conf_tid->tsid,
745 conf_tid->ps_scheme,
746 conf_tid->ack_policy,
747 conf_tid->apsd_conf[0],
748 conf_tid->apsd_conf[1]);
749 if (ret < 0)
750 goto out_free_memmap;
751 }
752
Luciano Coelho12419cc2010-02-18 13:25:44 +0200753 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200754 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300755 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200756 goto out_free_memmap;
757
758 /* Configure for CAM power saving (ie. always active) */
759 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
760 if (ret < 0)
761 goto out_free_memmap;
762
763 /* configure PM */
764 ret = wl1271_acx_pm_config(wl);
765 if (ret < 0)
766 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767
768 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200769
770 out_free_memmap:
771 kfree(wl->target_mem_map);
772 wl->target_mem_map = NULL;
773
774 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300775}
776
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300777static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200778{
Arik Nemtsovda032092011-08-25 12:43:15 +0300779 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200780
781 /* only regulate station links */
782 if (hlid < WL1271_AP_STA_HLID_START)
783 return;
784
785 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300786 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200787
788 /*
789 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300790 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200791 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300792 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200793 wl1271_ps_link_end(wl, hlid);
794
Arik Nemtsovda032092011-08-25 12:43:15 +0300795 /*
796 * Start high-level PS if the STA is asleep with enough blocks in FW.
797 * Make an exception if this is the only connected station. In this
798 * case FW-memory congestion is not a problem.
799 */
800 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200801 wl1271_ps_link_start(wl, hlid, true);
802}
803
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300804bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
805{
Arik Nemtsov04216da2011-08-14 13:17:38 +0300806 int id;
807
808 /* global/broadcast "stations" are always active */
809 if (hlid < WL1271_AP_STA_HLID_START)
810 return true;
811
812 id = hlid - WL1271_AP_STA_HLID_START;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300813 return test_bit(id, wl->ap_hlid_map);
814}
815
816static void wl12xx_irq_update_links_status(struct wl1271 *wl,
817 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200818{
819 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300820 u8 hlid, cnt;
821
822 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200823
824 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
825 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
826 wl1271_debug(DEBUG_PSM,
827 "link ps prev 0x%x cur 0x%x changed 0x%x",
828 wl->ap_fw_ps_map, cur_fw_ps_map,
829 wl->ap_fw_ps_map ^ cur_fw_ps_map);
830
831 wl->ap_fw_ps_map = cur_fw_ps_map;
832 }
833
834 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300835 if (!wl1271_is_active_sta(wl, hlid))
836 continue;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200837
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300838 cnt = status->tx_lnk_free_pkts[hlid] -
839 wl->links[hlid].prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200840
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300841 wl->links[hlid].prev_freed_pkts =
842 status->tx_lnk_free_pkts[hlid];
843 wl->links[hlid].allocated_pkts -= cnt;
844
845 wl12xx_irq_ps_regulate_link(wl, hlid,
846 wl->links[hlid].allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200847 }
848}
849
Eliad Peller4d56ad92011-08-14 13:17:05 +0300850static void wl12xx_fw_status(struct wl1271 *wl,
851 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300852{
Eliad Peller536129c2011-10-05 11:55:45 +0200853 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
854 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200855 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200856 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300857 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300858 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300859
Eliad Peller4d56ad92011-08-14 13:17:05 +0300860 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200861
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300862 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
863 "drv_rx_counter = %d, tx_results_counter = %d)",
864 status->intr,
865 status->fw_rx_counter,
866 status->drv_rx_counter,
867 status->tx_results_counter);
868
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300869 for (i = 0; i < NUM_TX_QUEUES; i++) {
870 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300871 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300872 (status->tx_released_pkts[i] -
873 wl->tx_pkts_freed[i]) & 0xff;
874
875 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
876 }
877
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300878 /* prevent wrap-around in total blocks counter */
879 if (likely(wl->tx_blocks_freed <=
880 le32_to_cpu(status->total_released_blks)))
881 freed_blocks = le32_to_cpu(status->total_released_blks) -
882 wl->tx_blocks_freed;
883 else
884 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
885 le32_to_cpu(status->total_released_blks);
886
Eliad Peller4d56ad92011-08-14 13:17:05 +0300887 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200888
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300889 wl->tx_allocated_blocks -= freed_blocks;
890
Eliad Peller4d56ad92011-08-14 13:17:05 +0300891 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200892
Eliad Peller4d56ad92011-08-14 13:17:05 +0300893 /*
894 * The FW might change the total number of TX memblocks before
895 * we get a notification about blocks being released. Thus, the
896 * available blocks calculation might yield a temporary result
897 * which is lower than the actual available blocks. Keeping in
898 * mind that only blocks that were allocated can be moved from
899 * TX to RX, tx_blocks_available should never decrease here.
900 */
901 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
902 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300903
Ido Yariva5225502010-10-12 14:49:10 +0200904 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200905 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200906 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300907
Eliad Peller4d56ad92011-08-14 13:17:05 +0300908 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller536129c2011-10-05 11:55:45 +0200909 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300910 wl12xx_irq_update_links_status(wl, status);
Eliad Peller4d56ad92011-08-14 13:17:05 +0300911
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300912 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200913 getnstimeofday(&ts);
914 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
915 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300916}
917
Ido Yariva6208652011-03-01 15:14:41 +0200918static void wl1271_flush_deferred_work(struct wl1271 *wl)
919{
920 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200921
Ido Yariva6208652011-03-01 15:14:41 +0200922 /* Pass all received frames to the network stack */
923 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
924 ieee80211_rx_ni(wl->hw, skb);
925
926 /* Return sent skbs to the network stack */
927 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300928 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200929}
930
931static void wl1271_netstack_work(struct work_struct *work)
932{
933 struct wl1271 *wl =
934 container_of(work, struct wl1271, netstack_work);
935
936 do {
937 wl1271_flush_deferred_work(wl);
938 } while (skb_queue_len(&wl->deferred_rx_queue));
939}
940
941#define WL1271_IRQ_MAX_LOOPS 256
942
943irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300944{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300946 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200947 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200948 struct wl1271 *wl = (struct wl1271 *)cookie;
949 bool done = false;
950 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200951 unsigned long flags;
952
953 /* TX might be handled here, avoid redundant work */
954 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
955 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956
Ido Yariv341b7cd2011-03-31 10:07:01 +0200957 /*
958 * In case edge triggered interrupt must be used, we cannot iterate
959 * more than once without introducing race conditions with the hardirq.
960 */
961 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
962 loopcount = 1;
963
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300964 mutex_lock(&wl->mutex);
965
966 wl1271_debug(DEBUG_IRQ, "IRQ work");
967
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200968 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300969 goto out;
970
Ido Yariva6208652011-03-01 15:14:41 +0200971 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972 if (ret < 0)
973 goto out;
974
Ido Yariva6208652011-03-01 15:14:41 +0200975 while (!done && loopcount--) {
976 /*
977 * In order to avoid a race with the hardirq, clear the flag
978 * before acknowledging the chip. Since the mutex is held,
979 * wl1271_ps_elp_wakeup cannot be called concurrently.
980 */
981 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
982 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200983
Eliad Peller4d56ad92011-08-14 13:17:05 +0300984 wl12xx_fw_status(wl, wl->fw_status);
985 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200986 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200987 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200988 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200989 continue;
990 }
991
Eliad Pellerccc83b02010-10-27 14:09:57 +0200992 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
993 wl1271_error("watchdog interrupt received! "
994 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300995 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200996
997 /* restarting the chip. ignore any other interrupt. */
998 goto out;
999 }
1000
Ido Yariva6208652011-03-01 15:14:41 +02001001 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001002 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
1003
Eliad Peller4d56ad92011-08-14 13:17:05 +03001004 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001005
Ido Yariva5225502010-10-12 14:49:10 +02001006 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +02001007 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001008 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001009 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +02001010 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001011 /*
1012 * In order to avoid starvation of the TX path,
1013 * call the work function directly.
1014 */
Eliad Peller536129c2011-10-05 11:55:45 +02001015 wl1271_tx_work_locked(wl, wl->vif);
Ido Yarivb07d4032011-03-01 15:14:43 +02001016 } else {
1017 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001018 }
1019
Ido Yariv8aad2462011-03-01 15:14:38 +02001020 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001021 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +02001022 (wl->tx_results_count & 0xff))
1023 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001024
1025 /* Make sure the deferred queues don't get too long */
1026 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1027 skb_queue_len(&wl->deferred_rx_queue);
1028 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1029 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001030 }
1031
1032 if (intr & WL1271_ACX_INTR_EVENT_A) {
1033 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1034 wl1271_event_handle(wl, 0);
1035 }
1036
1037 if (intr & WL1271_ACX_INTR_EVENT_B) {
1038 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1039 wl1271_event_handle(wl, 1);
1040 }
1041
1042 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1043 wl1271_debug(DEBUG_IRQ,
1044 "WL1271_ACX_INTR_INIT_COMPLETE");
1045
1046 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1047 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048 }
1049
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050 wl1271_ps_elp_sleep(wl);
1051
1052out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001053 spin_lock_irqsave(&wl->wl_lock, flags);
1054 /* In case TX was not handled here, queue TX work */
1055 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1056 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001057 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001058 ieee80211_queue_work(wl->hw, &wl->tx_work);
1059 spin_unlock_irqrestore(&wl->wl_lock, flags);
1060
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001061 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001062
1063 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001064}
Ido Yariva6208652011-03-01 15:14:41 +02001065EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001067static int wl1271_fetch_firmware(struct wl1271 *wl)
1068{
1069 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001070 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001071 int ret;
1072
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001073 if (wl->chip.id == CHIP_ID_1283_PG20)
1074 fw_name = WL128X_FW_NAME;
1075 else
1076 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001077
1078 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1079
1080 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081
1082 if (ret < 0) {
1083 wl1271_error("could not get firmware: %d", ret);
1084 return ret;
1085 }
1086
1087 if (fw->size % 4) {
1088 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1089 fw->size);
1090 ret = -EILSEQ;
1091 goto out;
1092 }
1093
Arik Nemtsov166d5042010-10-16 21:44:57 +02001094 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001095 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001096 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097
1098 if (!wl->fw) {
1099 wl1271_error("could not allocate memory for the firmware");
1100 ret = -ENOMEM;
1101 goto out;
1102 }
1103
1104 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001105 ret = 0;
1106
1107out:
1108 release_firmware(fw);
1109
1110 return ret;
1111}
1112
1113static int wl1271_fetch_nvs(struct wl1271 *wl)
1114{
1115 const struct firmware *fw;
1116 int ret;
1117
Shahar Levi5aa42342011-03-06 16:32:07 +02001118 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001119
1120 if (ret < 0) {
1121 wl1271_error("could not get nvs file: %d", ret);
1122 return ret;
1123 }
1124
Shahar Levibc765bf2011-03-06 16:32:10 +02001125 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001126
1127 if (!wl->nvs) {
1128 wl1271_error("could not allocate memory for the nvs file");
1129 ret = -ENOMEM;
1130 goto out;
1131 }
1132
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001133 wl->nvs_len = fw->size;
1134
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001135out:
1136 release_firmware(fw);
1137
1138 return ret;
1139}
1140
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001141void wl12xx_queue_recovery_work(struct wl1271 *wl)
1142{
1143 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1144 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1145}
1146
Ido Yariv95dac04f2011-06-06 14:57:06 +03001147size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1148{
1149 size_t len = 0;
1150
1151 /* The FW log is a length-value list, find where the log end */
1152 while (len < maxlen) {
1153 if (memblock[len] == 0)
1154 break;
1155 if (len + memblock[len] + 1 > maxlen)
1156 break;
1157 len += memblock[len] + 1;
1158 }
1159
1160 /* Make sure we have enough room */
1161 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1162
1163 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1164 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1165 wl->fwlog_size += len;
1166
1167 return len;
1168}
1169
1170static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1171{
1172 u32 addr;
1173 u32 first_addr;
1174 u8 *block;
1175
1176 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1177 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1178 (wl->conf.fwlog.mem_blocks == 0))
1179 return;
1180
1181 wl1271_info("Reading FW panic log");
1182
1183 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1184 if (!block)
1185 return;
1186
1187 /*
1188 * Make sure the chip is awake and the logger isn't active.
1189 * This might fail if the firmware hanged.
1190 */
1191 if (!wl1271_ps_elp_wakeup(wl))
1192 wl12xx_cmd_stop_fwlog(wl);
1193
1194 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001195 wl12xx_fw_status(wl, wl->fw_status);
1196 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001197 if (!first_addr)
1198 goto out;
1199
1200 /* Traverse the memory blocks linked list */
1201 addr = first_addr;
1202 do {
1203 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1204 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1205 false);
1206
1207 /*
1208 * Memory blocks are linked to one another. The first 4 bytes
1209 * of each memory block hold the hardware address of the next
1210 * one. The last memory block points to the first one.
1211 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001212 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001213 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1214 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1215 break;
1216 } while (addr && (addr != first_addr));
1217
1218 wake_up_interruptible(&wl->fwlog_waitq);
1219
1220out:
1221 kfree(block);
1222}
1223
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001224static void wl1271_recovery_work(struct work_struct *work)
1225{
1226 struct wl1271 *wl =
1227 container_of(work, struct wl1271, recovery_work);
1228
1229 mutex_lock(&wl->mutex);
1230
1231 if (wl->state != WL1271_STATE_ON)
1232 goto out;
1233
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001234 /* Avoid a recursive recovery */
1235 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1236
Ido Yariv95dac04f2011-06-06 14:57:06 +03001237 wl12xx_read_fwlog_panic(wl);
1238
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001239 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1240 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001241
Eliad Peller2a5bff02011-08-25 18:10:59 +03001242 BUG_ON(bug_on_recovery);
1243
Oz Krakowskib992c682011-06-26 10:36:02 +03001244 /*
1245 * Advance security sequence number to overcome potential progress
1246 * in the firmware during recovery. This doens't hurt if the network is
1247 * not encrypted.
1248 */
1249 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1250 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1251 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1252
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001253 /* Prevent spurious TX during FW restart */
1254 ieee80211_stop_queues(wl->hw);
1255
Luciano Coelho33c2c062011-05-10 14:46:02 +03001256 if (wl->sched_scanning) {
1257 ieee80211_sched_scan_stopped(wl->hw);
1258 wl->sched_scanning = false;
1259 }
1260
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001261 /* reboot the chipset */
Eliad Peller536129c2011-10-05 11:55:45 +02001262 __wl1271_op_remove_interface(wl, wl->vif, false);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001263
1264 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1265
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001266 ieee80211_restart_hw(wl->hw);
1267
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001268 /*
1269 * Its safe to enable TX now - the queues are stopped after a request
1270 * to restart the HW.
1271 */
1272 ieee80211_wake_queues(wl->hw);
1273
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001274out:
1275 mutex_unlock(&wl->mutex);
1276}
1277
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001278static void wl1271_fw_wakeup(struct wl1271 *wl)
1279{
1280 u32 elp_reg;
1281
1282 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001283 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001284}
1285
1286static int wl1271_setup(struct wl1271 *wl)
1287{
1288 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1289 if (!wl->fw_status)
1290 return -ENOMEM;
1291
1292 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1293 if (!wl->tx_res_if) {
1294 kfree(wl->fw_status);
1295 return -ENOMEM;
1296 }
1297
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001298 return 0;
1299}
1300
1301static int wl1271_chip_wakeup(struct wl1271 *wl)
1302{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001303 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001304 int ret = 0;
1305
Juuso Oikarinen01ac17ec2009-12-11 15:41:02 +02001306 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001307 ret = wl1271_power_on(wl);
1308 if (ret < 0)
1309 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001310 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001311 wl1271_io_reset(wl);
1312 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001313
1314 /* We don't need a real memory partition here, because we only want
1315 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001316 memset(&partition, 0, sizeof(partition));
1317 partition.reg.start = REGISTERS_BASE;
1318 partition.reg.size = REGISTERS_DOWN_SIZE;
1319 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001320
1321 /* ELP module wake up */
1322 wl1271_fw_wakeup(wl);
1323
1324 /* whal_FwCtrl_BootSm() */
1325
1326 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001327 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001328
1329 /* 1. check if chip id is valid */
1330
1331 switch (wl->chip.id) {
1332 case CHIP_ID_1271_PG10:
1333 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1334 wl->chip.id);
1335
1336 ret = wl1271_setup(wl);
1337 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001338 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339 break;
1340 case CHIP_ID_1271_PG20:
1341 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1342 wl->chip.id);
1343
1344 ret = wl1271_setup(wl);
1345 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001346 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001348 case CHIP_ID_1283_PG20:
1349 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1350 wl->chip.id);
1351
1352 ret = wl1271_setup(wl);
1353 if (ret < 0)
1354 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001355
Ido Yariv0da13da2011-03-31 10:06:58 +02001356 if (wl1271_set_block_size(wl))
1357 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001358 break;
1359 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001361 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001363 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364 }
1365
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001366 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367 ret = wl1271_fetch_firmware(wl);
1368 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001369 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370 }
1371
1372 /* No NVS from netlink, try to get it from the filesystem */
1373 if (wl->nvs == NULL) {
1374 ret = wl1271_fetch_nvs(wl);
1375 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001376 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001377 }
1378
1379out:
1380 return ret;
1381}
1382
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001383int wl1271_plt_start(struct wl1271 *wl)
1384{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001385 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001386 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001387 int ret;
1388
1389 mutex_lock(&wl->mutex);
1390
1391 wl1271_notice("power up");
1392
1393 if (wl->state != WL1271_STATE_OFF) {
1394 wl1271_error("cannot go into PLT state because not "
1395 "in off state: %d", wl->state);
1396 ret = -EBUSY;
1397 goto out;
1398 }
1399
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001400 while (retries) {
1401 retries--;
1402 ret = wl1271_chip_wakeup(wl);
1403 if (ret < 0)
1404 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001405
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001406 ret = wl1271_boot(wl);
1407 if (ret < 0)
1408 goto power_off;
1409
1410 ret = wl1271_plt_init(wl);
1411 if (ret < 0)
1412 goto irq_disable;
1413
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001414 wl->state = WL1271_STATE_PLT;
1415 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001416 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001417
Gery Kahn6f07b722011-07-18 14:21:49 +03001418 /* update hw/fw version info in wiphy struct */
1419 wiphy->hw_version = wl->chip.id;
1420 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1421 sizeof(wiphy->fw_version));
1422
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001423 goto out;
1424
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001425irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001426 mutex_unlock(&wl->mutex);
1427 /* Unlocking the mutex in the middle of handling is
1428 inherently unsafe. In this case we deem it safe to do,
1429 because we need to let any possibly pending IRQ out of
1430 the system (and while we are WL1271_STATE_OFF the IRQ
1431 work function will not do anything.) Also, any other
1432 possible concurrent operations will fail due to the
1433 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001434 wl1271_disable_interrupts(wl);
1435 wl1271_flush_deferred_work(wl);
1436 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001437 mutex_lock(&wl->mutex);
1438power_off:
1439 wl1271_power_off(wl);
1440 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001442 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1443 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444out:
1445 mutex_unlock(&wl->mutex);
1446
1447 return ret;
1448}
1449
Luciano Coelho4623ec72011-03-21 19:26:41 +02001450static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001451{
1452 int ret = 0;
1453
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454 wl1271_notice("power down");
1455
1456 if (wl->state != WL1271_STATE_PLT) {
1457 wl1271_error("cannot power down because not in PLT "
1458 "state: %d", wl->state);
1459 ret = -EBUSY;
1460 goto out;
1461 }
1462
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001463 wl1271_power_off(wl);
1464
1465 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001466 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001467
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001468 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001469 wl1271_disable_interrupts(wl);
1470 wl1271_flush_deferred_work(wl);
1471 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001472 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001473 mutex_lock(&wl->mutex);
1474out:
1475 return ret;
1476}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001477
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001478int wl1271_plt_stop(struct wl1271 *wl)
1479{
1480 int ret;
1481
1482 mutex_lock(&wl->mutex);
1483 ret = __wl1271_plt_stop(wl);
1484 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001485 return ret;
1486}
1487
Johannes Berg7bb45682011-02-24 14:42:06 +01001488static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001489{
1490 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02001491 struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb);
1492 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(control->control.vif);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001493 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001494 int q, mapping;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001495 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001496
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001497 mapping = skb_get_queue_mapping(skb);
1498 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001499
Eliad Peller536129c2011-10-05 11:55:45 +02001500 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03001501 hlid = wl12xx_tx_get_hlid_ap(wl, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001502
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001503 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001504
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001505 /* queue the packet */
Eliad Peller536129c2011-10-05 11:55:45 +02001506 if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov04216da2011-08-14 13:17:38 +03001507 if (!wl1271_is_active_sta(wl, hlid)) {
1508 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d",
1509 hlid, q);
1510 dev_kfree_skb(skb);
1511 goto out;
1512 }
1513
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001514 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1515 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1516 } else {
1517 skb_queue_tail(&wl->tx_queue[q], skb);
1518 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001519
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001520 wl->tx_queue_count[q]++;
1521
1522 /*
1523 * The workqueue is slow to process the tx_queue and we need stop
1524 * the queue here, otherwise the queue will get too long.
1525 */
1526 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1527 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1528 ieee80211_stop_queue(wl->hw, mapping);
1529 set_bit(q, &wl->stopped_queues_map);
1530 }
1531
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001532 /*
1533 * The chip specific setup must run before the first TX packet -
1534 * before that, the tx_work will not be initialized!
1535 */
1536
Ido Yarivb07d4032011-03-01 15:14:43 +02001537 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1538 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001539 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001540
Arik Nemtsov04216da2011-08-14 13:17:38 +03001541out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001542 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001543}
1544
Shahar Leviae47c452011-03-06 16:32:14 +02001545int wl1271_tx_dummy_packet(struct wl1271 *wl)
1546{
Ido Yariv990f5de2011-03-31 10:06:59 +02001547 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001548 int q;
1549
1550 /* no need to queue a new dummy packet if one is already pending */
1551 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1552 return 0;
1553
1554 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001555
Ido Yariv990f5de2011-03-31 10:06:59 +02001556 spin_lock_irqsave(&wl->wl_lock, flags);
1557 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001558 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001559 spin_unlock_irqrestore(&wl->wl_lock, flags);
1560
1561 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1562 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Peller536129c2011-10-05 11:55:45 +02001563 wl1271_tx_work_locked(wl, wl->vif);
Ido Yariv990f5de2011-03-31 10:06:59 +02001564
1565 /*
1566 * If the FW TX is busy, TX work will be scheduled by the threaded
1567 * interrupt handler function
1568 */
1569 return 0;
1570}
1571
1572/*
1573 * The size of the dummy packet should be at least 1400 bytes. However, in
1574 * order to minimize the number of bus transactions, aligning it to 512 bytes
1575 * boundaries could be beneficial, performance wise
1576 */
1577#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1578
Luciano Coelhocf27d862011-04-01 21:08:23 +03001579static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001580{
1581 struct sk_buff *skb;
1582 struct ieee80211_hdr_3addr *hdr;
1583 unsigned int dummy_packet_size;
1584
1585 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1586 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1587
1588 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001589 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001590 wl1271_warning("Failed to allocate a dummy packet skb");
1591 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001592 }
1593
1594 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1595
1596 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1597 memset(hdr, 0, sizeof(*hdr));
1598 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001599 IEEE80211_STYPE_NULLFUNC |
1600 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001601
Ido Yariv990f5de2011-03-31 10:06:59 +02001602 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001603
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001604 /* Dummy packets require the TID to be management */
1605 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001606
1607 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001608 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001609 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001610
Ido Yariv990f5de2011-03-31 10:06:59 +02001611 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001612}
1613
Ido Yariv990f5de2011-03-31 10:06:59 +02001614
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001615static struct notifier_block wl1271_dev_notifier = {
1616 .notifier_call = wl1271_dev_notify,
1617};
1618
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001619#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001620static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1621 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001622{
Eliad Pellere85d1622011-06-27 13:06:43 +03001623 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001624
Eliad Peller94390642011-05-13 11:57:13 +03001625 mutex_lock(&wl->mutex);
1626
Eliad Pellere85d1622011-06-27 13:06:43 +03001627 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1628 goto out_unlock;
1629
Eliad Peller94390642011-05-13 11:57:13 +03001630 ret = wl1271_ps_elp_wakeup(wl);
1631 if (ret < 0)
1632 goto out_unlock;
1633
1634 /* enter psm if needed*/
1635 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1636 DECLARE_COMPLETION_ONSTACK(compl);
1637
1638 wl->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001639 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001640 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001641 if (ret < 0)
1642 goto out_sleep;
1643
1644 /* we must unlock here so we will be able to get events */
1645 wl1271_ps_elp_sleep(wl);
1646 mutex_unlock(&wl->mutex);
1647
1648 ret = wait_for_completion_timeout(
1649 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1650 if (ret <= 0) {
1651 wl1271_warning("couldn't enter ps mode!");
1652 ret = -EBUSY;
1653 goto out;
1654 }
1655
1656 /* take mutex again, and wakeup */
1657 mutex_lock(&wl->mutex);
1658
1659 ret = wl1271_ps_elp_wakeup(wl);
1660 if (ret < 0)
1661 goto out_unlock;
1662 }
1663out_sleep:
1664 wl1271_ps_elp_sleep(wl);
1665out_unlock:
1666 mutex_unlock(&wl->mutex);
1667out:
1668 return ret;
1669
1670}
1671
Eliad Peller0603d892011-10-05 11:55:51 +02001672static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1673 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001674{
Eliad Pellere85d1622011-06-27 13:06:43 +03001675 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001676
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001677 mutex_lock(&wl->mutex);
1678
Eliad Pellere85d1622011-06-27 13:06:43 +03001679 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1680 goto out_unlock;
1681
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001682 ret = wl1271_ps_elp_wakeup(wl);
1683 if (ret < 0)
1684 goto out_unlock;
1685
Eliad Peller0603d892011-10-05 11:55:51 +02001686 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001687
1688 wl1271_ps_elp_sleep(wl);
1689out_unlock:
1690 mutex_unlock(&wl->mutex);
1691 return ret;
1692
1693}
1694
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001695static int wl1271_configure_suspend(struct wl1271 *wl,
1696 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001697{
Eliad Peller536129c2011-10-05 11:55:45 +02001698 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001699 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001700 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001701 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001702 return 0;
1703}
1704
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001705static void wl1271_configure_resume(struct wl1271 *wl,
1706 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001707{
1708 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001709 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1710 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001711
1712 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001713 return;
1714
1715 mutex_lock(&wl->mutex);
1716 ret = wl1271_ps_elp_wakeup(wl);
1717 if (ret < 0)
1718 goto out;
1719
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001720 if (is_sta) {
1721 /* exit psm if it wasn't configured */
1722 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001723 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001724 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001725 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001726 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001727 }
Eliad Peller94390642011-05-13 11:57:13 +03001728
1729 wl1271_ps_elp_sleep(wl);
1730out:
1731 mutex_unlock(&wl->mutex);
1732}
1733
Eliad Peller402e48612011-05-13 11:57:09 +03001734static int wl1271_op_suspend(struct ieee80211_hw *hw,
1735 struct cfg80211_wowlan *wow)
1736{
1737 struct wl1271 *wl = hw->priv;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001738 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
1739 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001740 int ret;
1741
Eliad Peller402e48612011-05-13 11:57:09 +03001742 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001743 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001744
Eliad Peller4a859df2011-06-06 12:21:52 +03001745 wl->wow_enabled = true;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001746 ret = wl1271_configure_suspend(wl, wlvif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001747 if (ret < 0) {
1748 wl1271_warning("couldn't prepare device to suspend");
1749 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001750 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001751 /* flush any remaining work */
1752 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001753
1754 /*
1755 * disable and re-enable interrupts in order to flush
1756 * the threaded_irq
1757 */
1758 wl1271_disable_interrupts(wl);
1759
1760 /*
1761 * set suspended flag to avoid triggering a new threaded_irq
1762 * work. no need for spinlock as interrupts are disabled.
1763 */
1764 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1765
1766 wl1271_enable_interrupts(wl);
1767 flush_work(&wl->tx_work);
1768 flush_delayed_work(&wl->pspoll_work);
1769 flush_delayed_work(&wl->elp_work);
1770
Eliad Peller402e48612011-05-13 11:57:09 +03001771 return 0;
1772}
1773
1774static int wl1271_op_resume(struct ieee80211_hw *hw)
1775{
1776 struct wl1271 *wl = hw->priv;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001777 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
1778 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001779 unsigned long flags;
1780 bool run_irq_work = false;
1781
Eliad Peller402e48612011-05-13 11:57:09 +03001782 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1783 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001784 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001785
1786 /*
1787 * re-enable irq_work enqueuing, and call irq_work directly if
1788 * there is a pending work.
1789 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001790 spin_lock_irqsave(&wl->wl_lock, flags);
1791 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1792 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1793 run_irq_work = true;
1794 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001795
Eliad Peller4a859df2011-06-06 12:21:52 +03001796 if (run_irq_work) {
1797 wl1271_debug(DEBUG_MAC80211,
1798 "run postponed irq_work directly");
1799 wl1271_irq(0, wl);
1800 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001801 }
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001802 wl1271_configure_resume(wl, wlvif);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001803 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001804
Eliad Peller402e48612011-05-13 11:57:09 +03001805 return 0;
1806}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001807#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001808
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001809static int wl1271_op_start(struct ieee80211_hw *hw)
1810{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001811 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1812
1813 /*
1814 * We have to delay the booting of the hardware because
1815 * we need to know the local MAC address before downloading and
1816 * initializing the firmware. The MAC address cannot be changed
1817 * after boot, and without the proper MAC address, the firmware
1818 * will not function properly.
1819 *
1820 * The MAC address is first known when the corresponding interface
1821 * is added. That is where we will initialize the hardware.
1822 */
1823
1824 return 0;
1825}
1826
1827static void wl1271_op_stop(struct ieee80211_hw *hw)
1828{
1829 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1830}
1831
Eliad Peller536129c2011-10-05 11:55:45 +02001832static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001833{
Eliad Peller536129c2011-10-05 11:55:45 +02001834 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001835 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001836 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001837 return WL1271_ROLE_P2P_GO;
1838 else
1839 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001840
1841 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001842 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001843 return WL1271_ROLE_P2P_CL;
1844 else
1845 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001846
Eliad Peller227e81e2011-08-14 13:17:26 +03001847 case BSS_TYPE_IBSS:
1848 return WL1271_ROLE_IBSS;
1849
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001850 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001851 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001852 }
1853 return WL12XX_INVALID_ROLE_TYPE;
1854}
1855
Eliad Peller87fbcb02011-10-05 11:55:41 +02001856static void wl12xx_init_vif_data(struct wl12xx_vif *wlvif)
1857{
Eliad Peller536129c2011-10-05 11:55:45 +02001858 wlvif->bss_type = MAX_BSS_TYPE;
Eliad Peller0603d892011-10-05 11:55:51 +02001859 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001860 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001861 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001862 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001863}
1864
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001865static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1866 struct ieee80211_vif *vif)
1867{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001868 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001869 struct wiphy *wiphy = hw->wiphy;
Eliad Peller536129c2011-10-05 11:55:45 +02001870 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001871 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001872 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001873 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02001874 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001875
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001876 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03001877 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001878
1879 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001880 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001881 wl1271_debug(DEBUG_MAC80211,
1882 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001883 ret = -EBUSY;
1884 goto out;
1885 }
Eliad Peller536129c2011-10-05 11:55:45 +02001886 wl12xx_init_vif_data(wlvif);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001887
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001888 /*
1889 * in some very corner case HW recovery scenarios its possible to
1890 * get here before __wl1271_op_remove_interface is complete, so
1891 * opt out if that is the case.
1892 */
1893 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1894 ret = -EBUSY;
1895 goto out;
1896 }
1897
Eliad Peller045c7452011-08-28 15:23:01 +03001898 switch (ieee80211_vif_type_p2p(vif)) {
1899 case NL80211_IFTYPE_P2P_CLIENT:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001900 wlvif->p2p = 1;
Eliad Peller045c7452011-08-28 15:23:01 +03001901 /* fall-through */
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001902 case NL80211_IFTYPE_STATION:
Eliad Peller536129c2011-10-05 11:55:45 +02001903 wlvif->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001904 break;
1905 case NL80211_IFTYPE_ADHOC:
Eliad Peller536129c2011-10-05 11:55:45 +02001906 wlvif->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001907 break;
Eliad Peller045c7452011-08-28 15:23:01 +03001908 case NL80211_IFTYPE_P2P_GO:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001909 wlvif->p2p = 1;
Eliad Peller045c7452011-08-28 15:23:01 +03001910 /* fall-through */
Arik Nemtsov038d9252010-10-16 21:53:24 +02001911 case NL80211_IFTYPE_AP:
Eliad Peller536129c2011-10-05 11:55:45 +02001912 wlvif->bss_type = BSS_TYPE_AP_BSS;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001913 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001914 default:
1915 ret = -EOPNOTSUPP;
1916 goto out;
1917 }
1918
Eliad Peller536129c2011-10-05 11:55:45 +02001919 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001920 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
1921 ret = -EINVAL;
1922 goto out;
1923 }
Eliad Peller784f6942011-10-05 11:55:39 +02001924 /*
1925 * we still need this in order to configure the fw
1926 * while uploading the nvs
1927 */
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001928 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001929
1930 if (wl->state != WL1271_STATE_OFF) {
1931 wl1271_error("cannot start because not in off state: %d",
1932 wl->state);
1933 ret = -EBUSY;
1934 goto out;
1935 }
1936
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001937 while (retries) {
1938 retries--;
1939 ret = wl1271_chip_wakeup(wl);
1940 if (ret < 0)
1941 goto power_off;
1942
1943 ret = wl1271_boot(wl);
1944 if (ret < 0)
1945 goto power_off;
1946
Eliad Peller92c77c72011-10-05 11:55:40 +02001947 ret = wl1271_hw_init(wl);
1948 if (ret < 0)
1949 goto irq_disable;
1950
Eliad Peller536129c2011-10-05 11:55:45 +02001951 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1952 wlvif->bss_type == BSS_TYPE_IBSS) {
Eliad Peller04e80792011-08-14 13:17:09 +03001953 /*
1954 * The device role is a special role used for
1955 * rx and tx frames prior to association (as
1956 * the STA role can get packets only from
1957 * its associated bssid)
1958 */
Eliad Peller784f6942011-10-05 11:55:39 +02001959 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller04e80792011-08-14 13:17:09 +03001960 WL1271_ROLE_DEVICE,
1961 &wl->dev_role_id);
1962 if (ret < 0)
1963 goto irq_disable;
1964 }
1965
Eliad Peller784f6942011-10-05 11:55:39 +02001966 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller0603d892011-10-05 11:55:51 +02001967 role_type, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001968 if (ret < 0)
1969 goto irq_disable;
1970
Eliad Peller92c77c72011-10-05 11:55:40 +02001971 ret = wl1271_init_vif_specific(wl, vif);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001972 if (ret < 0)
1973 goto irq_disable;
1974
Eliad Peller71125ab2010-10-28 21:46:43 +02001975 booted = true;
1976 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001977
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001978irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001979 mutex_unlock(&wl->mutex);
1980 /* Unlocking the mutex in the middle of handling is
1981 inherently unsafe. In this case we deem it safe to do,
1982 because we need to let any possibly pending IRQ out of
1983 the system (and while we are WL1271_STATE_OFF the IRQ
1984 work function will not do anything.) Also, any other
1985 possible concurrent operations will fail due to the
1986 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001987 wl1271_disable_interrupts(wl);
1988 wl1271_flush_deferred_work(wl);
1989 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001990 mutex_lock(&wl->mutex);
1991power_off:
1992 wl1271_power_off(wl);
1993 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001994
Eliad Peller71125ab2010-10-28 21:46:43 +02001995 if (!booted) {
1996 wl1271_error("firmware boot failed despite %d retries",
1997 WL1271_BOOT_RETRIES);
1998 goto out;
1999 }
2000
2001 wl->vif = vif;
2002 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002003 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01002004 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02002005
2006 /* update hw/fw version info in wiphy struct */
2007 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01002008 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02002009 sizeof(wiphy->fw_version));
2010
Luciano Coelhofb6a6812010-12-03 17:05:40 +02002011 /*
2012 * Now we know if 11a is supported (info from the NVS), so disable
2013 * 11a channels if not supported
2014 */
2015 if (!wl->enable_11a)
2016 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2017
2018 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2019 wl->enable_11a ? "" : "not ");
2020
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002021out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002022 mutex_unlock(&wl->mutex);
2023
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002024 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002025 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002026 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002027 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002028
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002029 return ret;
2030}
2031
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002032static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002033 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002034 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002035{
Eliad Peller536129c2011-10-05 11:55:45 +02002036 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002037 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002038
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002039 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002040
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002041 /* because of hardware recovery, we may get here twice */
2042 if (wl->state != WL1271_STATE_ON)
2043 return;
2044
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002045 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002046
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002047 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002048 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002049 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002050
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002051 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002052 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002053 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002054
Luciano Coelho08688d62010-07-08 17:50:07 +03002055 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002056 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002057 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002058 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002059 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002060 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002061 }
2062
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002063 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2064 /* disable active roles */
2065 ret = wl1271_ps_elp_wakeup(wl);
2066 if (ret < 0)
2067 goto deinit;
2068
Eliad Peller536129c2011-10-05 11:55:45 +02002069 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller04e80792011-08-14 13:17:09 +03002070 ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
2071 if (ret < 0)
2072 goto deinit;
2073 }
2074
Eliad Peller0603d892011-10-05 11:55:51 +02002075 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002076 if (ret < 0)
2077 goto deinit;
2078
2079 wl1271_ps_elp_sleep(wl);
2080 }
2081deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002082 /* clear all hlids (except system_hlid) */
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002083 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002084 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002085 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
2086 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002087
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002088 /*
2089 * this must be before the cancel_work calls below, so that the work
2090 * functions don't perform further work.
2091 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002092 wl->state = WL1271_STATE_OFF;
2093
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002094 mutex_unlock(&wl->mutex);
2095
Ido Yariva6208652011-03-01 15:14:41 +02002096 wl1271_disable_interrupts(wl);
2097 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02002098 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02002099 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002100 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03002101 del_timer_sync(&wl->rx_streaming_timer);
2102 cancel_work_sync(&wl->rx_streaming_enable_work);
2103 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002104 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02002105 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002106
2107 mutex_lock(&wl->mutex);
2108
2109 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002110 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002111 wl1271_power_off(wl);
2112
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002113 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002114
2115 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002116 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002117 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
2118 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002119 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002120 wl->tx_results_count = 0;
2121 wl->tx_packets_count = 0;
2122 wl->time_offset = 0;
2123 wl->session_counter = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03002124 wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
2125 wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002126 wl->vif = NULL;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002127 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002128 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002129 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02002130 wl->ap_fw_ps_map = 0;
2131 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002132 wl->sched_scanning = false;
Eliad Peller0603d892011-10-05 11:55:51 +02002133 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002134 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerc690ec82011-08-14 13:17:07 +03002135 memset(wl->roles_map, 0, sizeof(wl->roles_map));
2136 memset(wl->links_map, 0, sizeof(wl->links_map));
Eliad Peller251c1772011-08-14 13:17:17 +03002137 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Arik Nemtsovda032092011-08-25 12:43:15 +03002138 wl->active_sta_count = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002139
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002140 /* The system link is always allocated */
2141 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
2142
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002143 /*
2144 * this is performed after the cancel_work calls and the associated
2145 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2146 * get executed before all these vars have been reset.
2147 */
2148 wl->flags = 0;
2149
Eliad Peller4d56ad92011-08-14 13:17:05 +03002150 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002151
Arik Nemtsov742246f2011-08-14 13:17:33 +03002152 for (i = 0; i < NUM_TX_QUEUES; i++) {
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002153 wl->tx_pkts_freed[i] = 0;
Arik Nemtsov742246f2011-08-14 13:17:33 +03002154 wl->tx_allocated_pkts[i] = 0;
2155 }
Arik Nemtsovbf54e302011-08-14 13:17:32 +03002156
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002157 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002158
2159 kfree(wl->fw_status);
2160 wl->fw_status = NULL;
2161 kfree(wl->tx_res_if);
2162 wl->tx_res_if = NULL;
2163 kfree(wl->target_mem_map);
2164 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002165}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002166
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002167static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2168 struct ieee80211_vif *vif)
2169{
2170 struct wl1271 *wl = hw->priv;
2171
2172 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002173 /*
2174 * wl->vif can be null here if someone shuts down the interface
2175 * just when hardware recovery has been started.
2176 */
2177 if (wl->vif) {
2178 WARN_ON(wl->vif != vif);
Eliad Peller536129c2011-10-05 11:55:45 +02002179 __wl1271_op_remove_interface(wl, vif, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002180 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002181
Juuso Oikarinen67353292010-11-18 15:19:02 +02002182 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002183 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002184}
2185
Eliad Peller87fbcb02011-10-05 11:55:41 +02002186static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2187 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002188{
2189 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002190 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002191
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002192 /*
2193 * One of the side effects of the JOIN command is that is clears
2194 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2195 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002196 * Currently the only valid scenario for JOIN during association
2197 * is on roaming, in which case we will also be given new keys.
2198 * Keep the below message for now, unless it starts bothering
2199 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002200 */
2201 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2202 wl1271_info("JOIN while associated.");
2203
2204 if (set_assoc)
2205 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2206
Eliad Peller227e81e2011-08-14 13:17:26 +03002207 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002208 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002209 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002210 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002211 if (ret < 0)
2212 goto out;
2213
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002214 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2215 goto out;
2216
2217 /*
2218 * The join command disable the keep-alive mode, shut down its process,
2219 * and also clear the template config, so we need to reset it all after
2220 * the join. The acx_aid starts the keep-alive process, and the order
2221 * of the commands below is relevant.
2222 */
Eliad Peller0603d892011-10-05 11:55:51 +02002223 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002224 if (ret < 0)
2225 goto out;
2226
Eliad Peller0603d892011-10-05 11:55:51 +02002227 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002228 if (ret < 0)
2229 goto out;
2230
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002231 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002232 if (ret < 0)
2233 goto out;
2234
Eliad Peller0603d892011-10-05 11:55:51 +02002235 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2236 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002237 ACX_KEEP_ALIVE_TPL_VALID);
2238 if (ret < 0)
2239 goto out;
2240
2241out:
2242 return ret;
2243}
2244
Eliad Peller0603d892011-10-05 11:55:51 +02002245static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002246{
2247 int ret;
2248
Shahar Levi6d158ff2011-09-08 13:01:33 +03002249 if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags)) {
2250 wl12xx_cmd_stop_channel_switch(wl);
2251 ieee80211_chswitch_done(wl->vif, false);
2252 }
2253
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002254 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002255 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002256 if (ret < 0)
2257 goto out;
2258
Oz Krakowskib992c682011-06-26 10:36:02 +03002259 /* reset TX security counters on a clean disconnect */
2260 wl->tx_security_last_seq_lsb = 0;
2261 wl->tx_security_seq = 0;
2262
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002263out:
2264 return ret;
2265}
2266
Eliad Peller87fbcb02011-10-05 11:55:41 +02002267static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002268{
Eliad Peller87fbcb02011-10-05 11:55:41 +02002269 wlvif->basic_rate_set = wl->bitrate_masks[wl->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002270 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002271}
2272
Eliad Peller251c1772011-08-14 13:17:17 +03002273static bool wl12xx_is_roc(struct wl1271 *wl)
2274{
2275 u8 role_id;
2276
2277 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2278 if (role_id >= WL12XX_MAX_ROLES)
2279 return false;
2280
2281 return true;
2282}
2283
Eliad Peller87fbcb02011-10-05 11:55:41 +02002284static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2285 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002286{
2287 int ret;
2288
2289 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002290 /* no need to croc if we weren't busy (e.g. during boot) */
2291 if (wl12xx_is_roc(wl)) {
2292 ret = wl12xx_croc(wl, wl->dev_role_id);
2293 if (ret < 0)
2294 goto out;
2295
2296 ret = wl12xx_cmd_role_stop_dev(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002297 if (ret < 0)
2298 goto out;
2299 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002300 wlvif->rate_set =
2301 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2302 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002303 if (ret < 0)
2304 goto out;
2305 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002306 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002307 ACX_KEEP_ALIVE_TPL_INVALID);
2308 if (ret < 0)
2309 goto out;
2310 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2311 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002312 /* The current firmware only supports sched_scan in idle */
2313 if (wl->sched_scanning) {
2314 wl1271_scan_sched_scan_stop(wl);
2315 ieee80211_sched_scan_stopped(wl->hw);
2316 }
2317
Eliad Peller251c1772011-08-14 13:17:17 +03002318 ret = wl12xx_cmd_role_start_dev(wl);
2319 if (ret < 0)
2320 goto out;
2321
2322 ret = wl12xx_roc(wl, wl->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002323 if (ret < 0)
2324 goto out;
2325 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2326 }
2327
2328out:
2329 return ret;
2330}
2331
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002332static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2333{
2334 struct wl1271 *wl = hw->priv;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002335 struct ieee80211_vif *vif = wl->vif; /* TODO: reconfig all vifs */
2336 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002337 struct ieee80211_conf *conf = &hw->conf;
2338 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002339 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002340
2341 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2342
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002343 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2344 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002345 channel,
2346 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002347 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002348 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2349 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002350
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002351 /*
2352 * mac80211 will go to idle nearly immediately after transmitting some
2353 * frames, such as the deauth. To make sure those frames reach the air,
2354 * wait here until the TX queue is fully flushed.
2355 */
2356 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2357 (conf->flags & IEEE80211_CONF_IDLE))
2358 wl1271_tx_flush(wl);
2359
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002360 mutex_lock(&wl->mutex);
2361
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002362 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002363 /* we support configuring the channel and band while off */
2364 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2365 wl->band = conf->channel->band;
2366 wl->channel = channel;
2367 }
2368
Arik Nemtsov097f8822011-06-27 22:06:34 +03002369 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2370 wl->power_level = conf->power_level;
2371
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002372 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002373 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002374
Eliad Peller536129c2011-10-05 11:55:45 +02002375 is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002376
Ido Yariva6208652011-03-01 15:14:41 +02002377 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002378 if (ret < 0)
2379 goto out;
2380
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002381 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002382 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2383 ((wl->band != conf->channel->band) ||
2384 (wl->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002385 /* send all pending packets */
Eliad Peller536129c2011-10-05 11:55:45 +02002386 wl1271_tx_work_locked(wl, vif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002387 wl->band = conf->channel->band;
2388 wl->channel = channel;
2389
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002390 if (!is_ap) {
2391 /*
2392 * FIXME: the mac80211 should really provide a fixed
2393 * rate to use here. for now, just use the smallest
2394 * possible rate for the band as a fixed rate for
2395 * association frames and other control messages.
2396 */
2397 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002398 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002399
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002400 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002401 wl1271_tx_min_rate_get(wl,
2402 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002403 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002404 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002405 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002406 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002407
Eliad Peller251c1772011-08-14 13:17:17 +03002408 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2409 if (wl12xx_is_roc(wl)) {
2410 /* roaming */
2411 ret = wl12xx_croc(wl, wl->dev_role_id);
2412 if (ret < 0)
2413 goto out_sleep;
2414 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002415 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002416 if (ret < 0)
2417 wl1271_warning("cmd join on channel "
2418 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002419 } else {
2420 /*
2421 * change the ROC channel. do it only if we are
2422 * not idle. otherwise, CROC will be called
2423 * anyway.
2424 */
2425 if (wl12xx_is_roc(wl) &&
2426 !(conf->flags & IEEE80211_CONF_IDLE)) {
2427 ret = wl12xx_croc(wl, wl->dev_role_id);
2428 if (ret < 0)
2429 goto out_sleep;
2430
2431 ret = wl12xx_roc(wl, wl->dev_role_id);
2432 if (ret < 0)
2433 wl1271_warning("roc failed %d",
2434 ret);
2435 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002436 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002437 }
2438 }
2439
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002440 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002441 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002442 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002443 if (ret < 0)
2444 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002445 }
2446
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002447 /*
2448 * if mac80211 changes the PSM mode, make sure the mode is not
2449 * incorrectly changed after the pspoll failure active window.
2450 */
2451 if (changed & IEEE80211_CONF_CHANGE_PS)
2452 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2453
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002454 if (conf->flags & IEEE80211_CONF_PS &&
2455 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2456 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002457
2458 /*
2459 * We enter PSM only if we're already associated.
2460 * If we're not, we'll enter it when joining an SSID,
2461 * through the bss_info_changed() hook.
2462 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002463 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002464 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002465 ret = wl1271_ps_set_mode(wl, wlvif,
2466 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002467 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002468 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002469 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002470 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002471 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002472
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002473 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002474
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002475 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002476 ret = wl1271_ps_set_mode(wl, wlvif,
2477 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002478 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002479 }
2480
2481 if (conf->power_level != wl->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002482 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002483 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002484 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002485
2486 wl->power_level = conf->power_level;
2487 }
2488
2489out_sleep:
2490 wl1271_ps_elp_sleep(wl);
2491
2492out:
2493 mutex_unlock(&wl->mutex);
2494
2495 return ret;
2496}
2497
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002498struct wl1271_filter_params {
2499 bool enabled;
2500 int mc_list_length;
2501 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2502};
2503
Jiri Pirko22bedad2010-04-01 21:22:57 +00002504static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2505 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002506{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002507 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002508 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002509 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002510
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002511 if (unlikely(wl->state == WL1271_STATE_OFF))
2512 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002513
Juuso Oikarinen74441132009-10-13 12:47:53 +03002514 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002515 if (!fp) {
2516 wl1271_error("Out of memory setting filters.");
2517 return 0;
2518 }
2519
2520 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002521 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002522 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2523 fp->enabled = false;
2524 } else {
2525 fp->enabled = true;
2526 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002527 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002528 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002529 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002530 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002531 }
2532
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002533 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002534}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002535
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002536#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2537 FIF_ALLMULTI | \
2538 FIF_FCSFAIL | \
2539 FIF_BCN_PRBRESP_PROMISC | \
2540 FIF_CONTROL | \
2541 FIF_OTHER_BSS)
2542
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002543static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2544 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002545 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002546{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002547 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002548 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002549 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
2550 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2551
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002552 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002553
Arik Nemtsov7d057862010-10-16 19:25:35 +02002554 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2555 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002556
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002557 mutex_lock(&wl->mutex);
2558
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002559 *total &= WL1271_SUPPORTED_FILTERS;
2560 changed &= WL1271_SUPPORTED_FILTERS;
2561
2562 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002563 goto out;
2564
Ido Yariva6208652011-03-01 15:14:41 +02002565 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002566 if (ret < 0)
2567 goto out;
2568
Eliad Peller536129c2011-10-05 11:55:45 +02002569 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
Arik Nemtsov7d057862010-10-16 19:25:35 +02002570 if (*total & FIF_ALLMULTI)
Eliad Peller0603d892011-10-05 11:55:51 +02002571 ret = wl1271_acx_group_address_tbl(wl, wlvif, false,
2572 NULL, 0);
Arik Nemtsov7d057862010-10-16 19:25:35 +02002573 else if (fp)
Eliad Peller0603d892011-10-05 11:55:51 +02002574 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2575 fp->enabled,
Arik Nemtsov7d057862010-10-16 19:25:35 +02002576 fp->mc_list,
2577 fp->mc_list_length);
2578 if (ret < 0)
2579 goto out_sleep;
2580 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002581
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002582 /*
2583 * the fw doesn't provide an api to configure the filters. instead,
2584 * the filters configuration is based on the active roles / ROC
2585 * state.
2586 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002587
2588out_sleep:
2589 wl1271_ps_elp_sleep(wl);
2590
2591out:
2592 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002593 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002594}
2595
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002596static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2597 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2598 u16 tx_seq_16)
2599{
2600 struct wl1271_ap_key *ap_key;
2601 int i;
2602
2603 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2604
2605 if (key_size > MAX_KEY_SIZE)
2606 return -EINVAL;
2607
2608 /*
2609 * Find next free entry in ap_keys. Also check we are not replacing
2610 * an existing key.
2611 */
2612 for (i = 0; i < MAX_NUM_KEYS; i++) {
2613 if (wl->recorded_ap_keys[i] == NULL)
2614 break;
2615
2616 if (wl->recorded_ap_keys[i]->id == id) {
2617 wl1271_warning("trying to record key replacement");
2618 return -EINVAL;
2619 }
2620 }
2621
2622 if (i == MAX_NUM_KEYS)
2623 return -EBUSY;
2624
2625 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2626 if (!ap_key)
2627 return -ENOMEM;
2628
2629 ap_key->id = id;
2630 ap_key->key_type = key_type;
2631 ap_key->key_size = key_size;
2632 memcpy(ap_key->key, key, key_size);
2633 ap_key->hlid = hlid;
2634 ap_key->tx_seq_32 = tx_seq_32;
2635 ap_key->tx_seq_16 = tx_seq_16;
2636
2637 wl->recorded_ap_keys[i] = ap_key;
2638 return 0;
2639}
2640
2641static void wl1271_free_ap_keys(struct wl1271 *wl)
2642{
2643 int i;
2644
2645 for (i = 0; i < MAX_NUM_KEYS; i++) {
2646 kfree(wl->recorded_ap_keys[i]);
2647 wl->recorded_ap_keys[i] = NULL;
2648 }
2649}
2650
2651static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2652{
2653 int i, ret = 0;
2654 struct wl1271_ap_key *key;
2655 bool wep_key_added = false;
2656
2657 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002658 u8 hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002659 if (wl->recorded_ap_keys[i] == NULL)
2660 break;
2661
2662 key = wl->recorded_ap_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002663 hlid = key->hlid;
2664 if (hlid == WL12XX_INVALID_LINK_ID)
2665 hlid = wl->ap_bcast_hlid;
2666
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002667 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2668 key->id, key->key_type,
2669 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002670 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002671 key->tx_seq_16);
2672 if (ret < 0)
2673 goto out;
2674
2675 if (key->key_type == KEY_WEP)
2676 wep_key_added = true;
2677 }
2678
2679 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002680 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002681 wl->ap_bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002682 if (ret < 0)
2683 goto out;
2684 }
2685
2686out:
2687 wl1271_free_ap_keys(wl);
2688 return ret;
2689}
2690
Eliad Peller536129c2011-10-05 11:55:45 +02002691static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2692 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002693 u8 key_size, const u8 *key, u32 tx_seq_32,
2694 u16 tx_seq_16, struct ieee80211_sta *sta)
2695{
2696 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002697 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002698
2699 if (is_ap) {
2700 struct wl1271_station *wl_sta;
2701 u8 hlid;
2702
2703 if (sta) {
2704 wl_sta = (struct wl1271_station *)sta->drv_priv;
2705 hlid = wl_sta->hlid;
2706 } else {
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002707 hlid = wl->ap_bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002708 }
2709
2710 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2711 /*
2712 * We do not support removing keys after AP shutdown.
2713 * Pretend we do to make mac80211 happy.
2714 */
2715 if (action != KEY_ADD_OR_REPLACE)
2716 return 0;
2717
2718 ret = wl1271_record_ap_key(wl, id,
2719 key_type, key_size,
2720 key, hlid, tx_seq_32,
2721 tx_seq_16);
2722 } else {
2723 ret = wl1271_cmd_set_ap_key(wl, action,
2724 id, key_type, key_size,
2725 key, hlid, tx_seq_32,
2726 tx_seq_16);
2727 }
2728
2729 if (ret < 0)
2730 return ret;
2731 } else {
2732 const u8 *addr;
2733 static const u8 bcast_addr[ETH_ALEN] = {
2734 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2735 };
2736
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002737 /*
2738 * A STA set to GEM cipher requires 2 tx spare blocks.
2739 * Return to default value when GEM cipher key is removed
2740 */
2741 if (key_type == KEY_GEM) {
2742 if (action == KEY_ADD_OR_REPLACE)
2743 wl->tx_spare_blocks = 2;
2744 else if (action == KEY_REMOVE)
2745 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2746 }
2747
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002748 addr = sta ? sta->addr : bcast_addr;
2749
2750 if (is_zero_ether_addr(addr)) {
2751 /* We dont support TX only encryption */
2752 return -EOPNOTSUPP;
2753 }
2754
2755 /* The wl1271 does not allow to remove unicast keys - they
2756 will be cleared automatically on next CMD_JOIN. Ignore the
2757 request silently, as we dont want the mac80211 to emit
2758 an error message. */
2759 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2760 return 0;
2761
Eliad Peller010d3d32011-08-14 13:17:31 +03002762 /* don't remove key if hlid was already deleted */
2763 if (action == KEY_REMOVE &&
2764 wl->sta_hlid == WL12XX_INVALID_LINK_ID)
2765 return 0;
2766
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002767 ret = wl1271_cmd_set_sta_key(wl, action,
2768 id, key_type, key_size,
2769 key, addr, tx_seq_32,
2770 tx_seq_16);
2771 if (ret < 0)
2772 return ret;
2773
2774 /* the default WEP key needs to be configured at least once */
2775 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002776 ret = wl12xx_cmd_set_default_wep_key(wl,
2777 wl->default_key,
2778 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002779 if (ret < 0)
2780 return ret;
2781 }
2782 }
2783
2784 return 0;
2785}
2786
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002787static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2788 struct ieee80211_vif *vif,
2789 struct ieee80211_sta *sta,
2790 struct ieee80211_key_conf *key_conf)
2791{
2792 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002793 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002794 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002795 u32 tx_seq_32 = 0;
2796 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002797 u8 key_type;
2798
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002799 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2800
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002801 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002802 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002803 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002804 key_conf->keylen, key_conf->flags);
2805 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2806
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002807 mutex_lock(&wl->mutex);
2808
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002809 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2810 ret = -EAGAIN;
2811 goto out_unlock;
2812 }
2813
Ido Yariva6208652011-03-01 15:14:41 +02002814 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002815 if (ret < 0)
2816 goto out_unlock;
2817
Johannes Berg97359d12010-08-10 09:46:38 +02002818 switch (key_conf->cipher) {
2819 case WLAN_CIPHER_SUITE_WEP40:
2820 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002821 key_type = KEY_WEP;
2822
2823 key_conf->hw_key_idx = key_conf->keyidx;
2824 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002825 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002826 key_type = KEY_TKIP;
2827
2828 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002829 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2830 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002831 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002832 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002833 key_type = KEY_AES;
2834
2835 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002836 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2837 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002838 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002839 case WL1271_CIPHER_SUITE_GEM:
2840 key_type = KEY_GEM;
2841 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2842 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2843 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002844 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002845 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002846
2847 ret = -EOPNOTSUPP;
2848 goto out_sleep;
2849 }
2850
2851 switch (cmd) {
2852 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002853 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002854 key_conf->keyidx, key_type,
2855 key_conf->keylen, key_conf->key,
2856 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002857 if (ret < 0) {
2858 wl1271_error("Could not add or replace key");
2859 goto out_sleep;
2860 }
2861 break;
2862
2863 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002864 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002865 key_conf->keyidx, key_type,
2866 key_conf->keylen, key_conf->key,
2867 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002868 if (ret < 0) {
2869 wl1271_error("Could not remove key");
2870 goto out_sleep;
2871 }
2872 break;
2873
2874 default:
2875 wl1271_error("Unsupported key cmd 0x%x", cmd);
2876 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002877 break;
2878 }
2879
2880out_sleep:
2881 wl1271_ps_elp_sleep(wl);
2882
2883out_unlock:
2884 mutex_unlock(&wl->mutex);
2885
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002886 return ret;
2887}
2888
2889static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002890 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002891 struct cfg80211_scan_request *req)
2892{
2893 struct wl1271 *wl = hw->priv;
2894 int ret;
2895 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002896 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002897
2898 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2899
2900 if (req->n_ssids) {
2901 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002902 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002903 }
2904
2905 mutex_lock(&wl->mutex);
2906
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002907 if (wl->state == WL1271_STATE_OFF) {
2908 /*
2909 * We cannot return -EBUSY here because cfg80211 will expect
2910 * a call to ieee80211_scan_completed if we do - in this case
2911 * there won't be any call.
2912 */
2913 ret = -EAGAIN;
2914 goto out;
2915 }
2916
Ido Yariva6208652011-03-01 15:14:41 +02002917 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002918 if (ret < 0)
2919 goto out;
2920
Eliad Peller251c1772011-08-14 13:17:17 +03002921 /* cancel ROC before scanning */
2922 if (wl12xx_is_roc(wl)) {
2923 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2924 /* don't allow scanning right now */
2925 ret = -EBUSY;
2926 goto out_sleep;
2927 }
2928 wl12xx_croc(wl, wl->dev_role_id);
2929 wl12xx_cmd_role_stop_dev(wl);
2930 }
2931
Eliad Peller784f6942011-10-05 11:55:39 +02002932 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002933out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002934 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002935out:
2936 mutex_unlock(&wl->mutex);
2937
2938 return ret;
2939}
2940
Eliad Peller73ecce32011-06-27 13:06:45 +03002941static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2942 struct ieee80211_vif *vif)
2943{
2944 struct wl1271 *wl = hw->priv;
2945 int ret;
2946
2947 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2948
2949 mutex_lock(&wl->mutex);
2950
2951 if (wl->state == WL1271_STATE_OFF)
2952 goto out;
2953
2954 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2955 goto out;
2956
2957 ret = wl1271_ps_elp_wakeup(wl);
2958 if (ret < 0)
2959 goto out;
2960
2961 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2962 ret = wl1271_scan_stop(wl);
2963 if (ret < 0)
2964 goto out_sleep;
2965 }
2966 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2967 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002968 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03002969 wl->scan.req = NULL;
2970 ieee80211_scan_completed(wl->hw, true);
2971
2972out_sleep:
2973 wl1271_ps_elp_sleep(wl);
2974out:
2975 mutex_unlock(&wl->mutex);
2976
2977 cancel_delayed_work_sync(&wl->scan_complete_work);
2978}
2979
Luciano Coelho33c2c062011-05-10 14:46:02 +03002980static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2981 struct ieee80211_vif *vif,
2982 struct cfg80211_sched_scan_request *req,
2983 struct ieee80211_sched_scan_ies *ies)
2984{
2985 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002986 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03002987 int ret;
2988
2989 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2990
2991 mutex_lock(&wl->mutex);
2992
2993 ret = wl1271_ps_elp_wakeup(wl);
2994 if (ret < 0)
2995 goto out;
2996
Eliad Peller536129c2011-10-05 11:55:45 +02002997 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03002998 if (ret < 0)
2999 goto out_sleep;
3000
Eliad Peller536129c2011-10-05 11:55:45 +02003001 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003002 if (ret < 0)
3003 goto out_sleep;
3004
3005 wl->sched_scanning = true;
3006
3007out_sleep:
3008 wl1271_ps_elp_sleep(wl);
3009out:
3010 mutex_unlock(&wl->mutex);
3011 return ret;
3012}
3013
3014static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3015 struct ieee80211_vif *vif)
3016{
3017 struct wl1271 *wl = hw->priv;
3018 int ret;
3019
3020 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3021
3022 mutex_lock(&wl->mutex);
3023
3024 ret = wl1271_ps_elp_wakeup(wl);
3025 if (ret < 0)
3026 goto out;
3027
3028 wl1271_scan_sched_scan_stop(wl);
3029
3030 wl1271_ps_elp_sleep(wl);
3031out:
3032 mutex_unlock(&wl->mutex);
3033}
3034
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003035static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3036{
3037 struct wl1271 *wl = hw->priv;
3038 int ret = 0;
3039
3040 mutex_lock(&wl->mutex);
3041
3042 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3043 ret = -EAGAIN;
3044 goto out;
3045 }
3046
Ido Yariva6208652011-03-01 15:14:41 +02003047 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003048 if (ret < 0)
3049 goto out;
3050
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003051 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003052 if (ret < 0)
3053 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3054
3055 wl1271_ps_elp_sleep(wl);
3056
3057out:
3058 mutex_unlock(&wl->mutex);
3059
3060 return ret;
3061}
3062
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003063static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3064{
3065 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003066 struct ieee80211_vif *vif = wl->vif;
3067 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003068 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003069
3070 mutex_lock(&wl->mutex);
3071
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003072 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3073 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003074 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003075 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003076
Ido Yariva6208652011-03-01 15:14:41 +02003077 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003078 if (ret < 0)
3079 goto out;
3080
Eliad Peller0603d892011-10-05 11:55:51 +02003081 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003082 if (ret < 0)
3083 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
3084
3085 wl1271_ps_elp_sleep(wl);
3086
3087out:
3088 mutex_unlock(&wl->mutex);
3089
3090 return ret;
3091}
3092
Eliad Peller1fe9f162011-10-05 11:55:48 +02003093static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003094 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003095{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003096 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003097 u8 ssid_len;
3098 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3099 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003100
Eliad Peller889cb362011-05-01 09:56:45 +03003101 if (!ptr) {
3102 wl1271_error("No SSID in IEs!");
3103 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003104 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003105
Eliad Peller889cb362011-05-01 09:56:45 +03003106 ssid_len = ptr[1];
3107 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3108 wl1271_error("SSID is too long!");
3109 return -EINVAL;
3110 }
3111
Eliad Peller1fe9f162011-10-05 11:55:48 +02003112 wlvif->ssid_len = ssid_len;
3113 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003114 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003115}
3116
Eliad Pellerd48055d2011-09-15 12:07:04 +03003117static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3118{
3119 int len;
3120 const u8 *next, *end = skb->data + skb->len;
3121 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3122 skb->len - ieoffset);
3123 if (!ie)
3124 return;
3125 len = ie[1] + 2;
3126 next = ie + len;
3127 memmove(ie, next, end - next);
3128 skb_trim(skb, skb->len - len);
3129}
3130
Eliad Peller26b4bf22011-09-15 12:07:05 +03003131static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3132 unsigned int oui, u8 oui_type,
3133 int ieoffset)
3134{
3135 int len;
3136 const u8 *next, *end = skb->data + skb->len;
3137 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3138 skb->data + ieoffset,
3139 skb->len - ieoffset);
3140 if (!ie)
3141 return;
3142 len = ie[1] + 2;
3143 next = ie + len;
3144 memmove(ie, next, end - next);
3145 skb_trim(skb, skb->len - len);
3146}
3147
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003148static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
Eliad Peller1fe9f162011-10-05 11:55:48 +02003149 struct ieee80211_vif *vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003150 u8 *probe_rsp_data,
3151 size_t probe_rsp_len,
3152 u32 rates)
3153{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003154 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3155 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003156 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3157 int ssid_ie_offset, ie_offset, templ_len;
3158 const u8 *ptr;
3159
3160 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003161 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003162 return wl1271_cmd_template_set(wl,
3163 CMD_TEMPL_AP_PROBE_RESPONSE,
3164 probe_rsp_data,
3165 probe_rsp_len, 0,
3166 rates);
3167
3168 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3169 wl1271_error("probe_rsp template too big");
3170 return -EINVAL;
3171 }
3172
3173 /* start searching from IE offset */
3174 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3175
3176 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3177 probe_rsp_len - ie_offset);
3178 if (!ptr) {
3179 wl1271_error("No SSID in beacon!");
3180 return -EINVAL;
3181 }
3182
3183 ssid_ie_offset = ptr - probe_rsp_data;
3184 ptr += (ptr[1] + 2);
3185
3186 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3187
3188 /* insert SSID from bss_conf */
3189 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3190 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3191 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3192 bss_conf->ssid, bss_conf->ssid_len);
3193 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3194
3195 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3196 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3197 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3198
3199 return wl1271_cmd_template_set(wl,
3200 CMD_TEMPL_AP_PROBE_RESPONSE,
3201 probe_rsp_templ,
3202 templ_len, 0,
3203 rates);
3204}
3205
Arik Nemtsove78a2872010-10-16 19:07:21 +02003206static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003207 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003208 struct ieee80211_bss_conf *bss_conf,
3209 u32 changed)
3210{
Eliad Peller0603d892011-10-05 11:55:51 +02003211 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003212 int ret = 0;
3213
3214 if (changed & BSS_CHANGED_ERP_SLOT) {
3215 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003216 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003217 else
Eliad Peller0603d892011-10-05 11:55:51 +02003218 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003219 if (ret < 0) {
3220 wl1271_warning("Set slot time failed %d", ret);
3221 goto out;
3222 }
3223 }
3224
3225 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3226 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003227 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003228 else
Eliad Peller0603d892011-10-05 11:55:51 +02003229 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003230 }
3231
3232 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3233 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003234 ret = wl1271_acx_cts_protect(wl, wlvif,
3235 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003236 else
Eliad Peller0603d892011-10-05 11:55:51 +02003237 ret = wl1271_acx_cts_protect(wl, wlvif,
3238 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003239 if (ret < 0) {
3240 wl1271_warning("Set ctsprotect failed %d", ret);
3241 goto out;
3242 }
3243 }
3244
3245out:
3246 return ret;
3247}
3248
3249static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3250 struct ieee80211_vif *vif,
3251 struct ieee80211_bss_conf *bss_conf,
3252 u32 changed)
3253{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003254 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003255 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003256 int ret = 0;
3257
3258 if ((changed & BSS_CHANGED_BEACON_INT)) {
3259 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3260 bss_conf->beacon_int);
3261
3262 wl->beacon_int = bss_conf->beacon_int;
3263 }
3264
3265 if ((changed & BSS_CHANGED_BEACON)) {
3266 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003267 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003268 int ieoffset = offsetof(struct ieee80211_mgmt,
3269 u.beacon.variable);
3270 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3271 u16 tmpl_id;
3272
3273 if (!beacon)
3274 goto out;
3275
3276 wl1271_debug(DEBUG_MASTER, "beacon updated");
3277
Eliad Peller1fe9f162011-10-05 11:55:48 +02003278 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003279 if (ret < 0) {
3280 dev_kfree_skb(beacon);
3281 goto out;
3282 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003283 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003284 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3285 CMD_TEMPL_BEACON;
3286 ret = wl1271_cmd_template_set(wl, tmpl_id,
3287 beacon->data,
3288 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003289 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003290 if (ret < 0) {
3291 dev_kfree_skb(beacon);
3292 goto out;
3293 }
3294
Eliad Pellerd48055d2011-09-15 12:07:04 +03003295 /* remove TIM ie from probe response */
3296 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3297
Eliad Peller26b4bf22011-09-15 12:07:05 +03003298 /*
3299 * remove p2p ie from probe response.
3300 * the fw reponds to probe requests that don't include
3301 * the p2p ie. probe requests with p2p ie will be passed,
3302 * and will be responded by the supplicant (the spec
3303 * forbids including the p2p ie when responding to probe
3304 * requests that didn't include it).
3305 */
3306 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3307 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3308
Arik Nemtsove78a2872010-10-16 19:07:21 +02003309 hdr = (struct ieee80211_hdr *) beacon->data;
3310 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3311 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003312 if (is_ap)
Eliad Peller1fe9f162011-10-05 11:55:48 +02003313 ret = wl1271_ap_set_probe_resp_tmpl(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003314 beacon->data,
3315 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003316 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003317 else
3318 ret = wl1271_cmd_template_set(wl,
3319 CMD_TEMPL_PROBE_RESPONSE,
3320 beacon->data,
3321 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003322 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003323 dev_kfree_skb(beacon);
3324 if (ret < 0)
3325 goto out;
3326 }
3327
3328out:
3329 return ret;
3330}
3331
3332/* AP mode changes */
3333static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003334 struct ieee80211_vif *vif,
3335 struct ieee80211_bss_conf *bss_conf,
3336 u32 changed)
3337{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003338 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003339 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003340
Arik Nemtsove78a2872010-10-16 19:07:21 +02003341 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3342 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003343
Eliad Peller87fbcb02011-10-05 11:55:41 +02003344 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003345 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003346 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003347 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003348
Eliad Peller87fbcb02011-10-05 11:55:41 +02003349 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003350 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003351 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003352 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003353 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003354
Eliad Peller784f6942011-10-05 11:55:39 +02003355 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003356 if (ret < 0)
3357 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003358 }
3359
Arik Nemtsove78a2872010-10-16 19:07:21 +02003360 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3361 if (ret < 0)
3362 goto out;
3363
3364 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3365 if (bss_conf->enable_beacon) {
3366 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003367 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003368 if (ret < 0)
3369 goto out;
3370
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003371 ret = wl1271_ap_init_hwenc(wl);
3372 if (ret < 0)
3373 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003374
3375 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3376 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003377 }
3378 } else {
3379 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003380 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003381 if (ret < 0)
3382 goto out;
3383
3384 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3385 wl1271_debug(DEBUG_AP, "stopped AP");
3386 }
3387 }
3388 }
3389
Eliad Peller0603d892011-10-05 11:55:51 +02003390 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003391 if (ret < 0)
3392 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003393
3394 /* Handle HT information change */
3395 if ((changed & BSS_CHANGED_HT) &&
3396 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003397 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003398 bss_conf->ht_operation_mode);
3399 if (ret < 0) {
3400 wl1271_warning("Set ht information failed %d", ret);
3401 goto out;
3402 }
3403 }
3404
Arik Nemtsove78a2872010-10-16 19:07:21 +02003405out:
3406 return;
3407}
3408
3409/* STA/IBSS mode changes */
3410static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3411 struct ieee80211_vif *vif,
3412 struct ieee80211_bss_conf *bss_conf,
3413 u32 changed)
3414{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003415 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003416 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003417 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003418 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003419 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003420 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003421 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003422 bool sta_exists = false;
3423 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003424
3425 if (is_ibss) {
3426 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3427 changed);
3428 if (ret < 0)
3429 goto out;
3430 }
3431
Eliad Peller227e81e2011-08-14 13:17:26 +03003432 if (changed & BSS_CHANGED_IBSS) {
3433 if (bss_conf->ibss_joined) {
3434 set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
3435 ibss_joined = true;
3436 } else {
3437 if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
3438 &wl->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003439 wl1271_unjoin(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003440 wl12xx_cmd_role_start_dev(wl);
3441 wl12xx_roc(wl, wl->dev_role_id);
3442 }
3443 }
3444 }
3445
3446 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003447 do_join = true;
3448
3449 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003450 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003451 do_join = true;
3452
Eliad Peller227e81e2011-08-14 13:17:26 +03003453 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003454 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3455 bss_conf->enable_beacon ? "enabled" : "disabled");
3456
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003457 do_join = true;
3458 }
3459
Arik Nemtsove78a2872010-10-16 19:07:21 +02003460 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003461 bool enable = false;
3462 if (bss_conf->cqm_rssi_thold)
3463 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003464 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003465 bss_conf->cqm_rssi_thold,
3466 bss_conf->cqm_rssi_hyst);
3467 if (ret < 0)
3468 goto out;
3469 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3470 }
3471
Eliad Pellercdf09492011-10-05 11:55:44 +02003472 if (changed & BSS_CHANGED_BSSID)
3473 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003474 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003475 if (ret < 0)
3476 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003477
Eliad Peller784f6942011-10-05 11:55:39 +02003478 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003479 if (ret < 0)
3480 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003481
Eliad Pellerfa287b82010-12-26 09:27:50 +01003482 /* Need to update the BSSID (for filtering etc) */
3483 do_join = true;
3484 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003485
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003486 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3487 rcu_read_lock();
3488 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3489 if (!sta)
3490 goto sta_not_found;
3491
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003492 /* save the supp_rates of the ap */
3493 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3494 if (sta->ht_cap.ht_supported)
3495 sta_rate_set |=
3496 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003497 sta_ht_cap = sta->ht_cap;
3498 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003499
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003500sta_not_found:
3501 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003502 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003503
Arik Nemtsove78a2872010-10-16 19:07:21 +02003504 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003505 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003506 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003507 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003508 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003509 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003510
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003511 wl->ps_poll_failures = 0;
3512
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003513 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003514 * use basic rates from AP, and determine lowest rate
3515 * to use with control frames.
3516 */
3517 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003518 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003519 wl1271_tx_enabled_rates_get(wl, rates,
3520 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003521 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003522 wl1271_tx_min_rate_get(wl,
3523 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003524 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003525 wlvif->rate_set =
3526 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003527 sta_rate_set,
3528 wl->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003529 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003530 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003531 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003532
3533 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003534 * with wl1271, we don't need to update the
3535 * beacon_int and dtim_period, because the firmware
3536 * updates it by itself when the first beacon is
3537 * received after a join.
3538 */
Eliad Peller6840e372011-10-05 11:55:50 +02003539 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003540 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003541 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003542
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003543 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003544 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003545 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003546 dev_kfree_skb(wlvif->probereq);
3547 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
3548 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003549 ieoffset = offsetof(struct ieee80211_mgmt,
3550 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003551 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003552
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003553 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003554 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003555 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003556 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003557 } else {
3558 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003559 bool was_assoc =
3560 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3561 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003562 bool was_ifup =
3563 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3564 &wl->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003565 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003566
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003567 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003568 dev_kfree_skb(wlvif->probereq);
3569 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003570
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003571 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003572 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003573
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003574 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003575 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003576 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003577 wl1271_tx_min_rate_get(wl,
3578 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003579 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003580 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003581 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003582
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003583 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003584 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003585
3586 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003587 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003588 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003589 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003590
3591 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003592 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003593 u32 conf_flags = wl->hw->conf.flags;
3594 /*
3595 * we might have to disable roc, if there was
3596 * no IF_OPER_UP notification.
3597 */
3598 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003599 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003600 if (ret < 0)
3601 goto out;
3602 }
3603 /*
3604 * (we also need to disable roc in case of
3605 * roaming on the same channel. until we will
3606 * have a better flow...)
3607 */
3608 if (test_bit(wl->dev_role_id, wl->roc_map)) {
3609 ret = wl12xx_croc(wl, wl->dev_role_id);
3610 if (ret < 0)
3611 goto out;
3612 }
3613
Eliad Peller0603d892011-10-05 11:55:51 +02003614 wl1271_unjoin(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003615 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
3616 wl12xx_cmd_role_start_dev(wl);
3617 wl12xx_roc(wl, wl->dev_role_id);
3618 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003619 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003620 }
3621 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003622
Eliad Pellerd192d262011-05-24 14:33:08 +03003623 if (changed & BSS_CHANGED_IBSS) {
3624 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3625 bss_conf->ibss_joined);
3626
3627 if (bss_conf->ibss_joined) {
3628 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003629 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003630 wl1271_tx_enabled_rates_get(wl, rates,
3631 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003632 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003633 wl1271_tx_min_rate_get(wl,
3634 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003635
Shahar Levi06b660e2011-09-05 13:54:36 +03003636 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003637 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3638 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003639 if (ret < 0)
3640 goto out;
3641 }
3642 }
3643
Eliad Peller0603d892011-10-05 11:55:51 +02003644 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003645 if (ret < 0)
3646 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003647
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003648 if (changed & BSS_CHANGED_ARP_FILTER) {
3649 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003650 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003651
Eliad Pellerc5312772010-12-09 11:31:27 +02003652 if (bss_conf->arp_addr_cnt == 1 &&
3653 bss_conf->arp_filter_enabled) {
3654 /*
3655 * The template should have been configured only upon
3656 * association. however, it seems that the correct ip
3657 * isn't being set (when sending), so we have to
3658 * reconfigure the template upon every ip change.
3659 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003660 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003661 if (ret < 0) {
3662 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003663 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003664 }
3665
Eliad Peller0603d892011-10-05 11:55:51 +02003666 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003667 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003668 addr);
3669 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003670 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003671
3672 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003673 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003674 }
3675
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003676 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003677 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003678 if (ret < 0) {
3679 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003680 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003681 }
Eliad Peller251c1772011-08-14 13:17:17 +03003682
3683 /* ROC until connected (after EAPOL exchange) */
3684 if (!is_ibss) {
Eliad Peller0603d892011-10-05 11:55:51 +02003685 ret = wl12xx_roc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003686 if (ret < 0)
3687 goto out;
3688
3689 wl1271_check_operstate(wl,
3690 ieee80211_get_operstate(vif));
3691 }
3692 /*
3693 * stop device role if started (we might already be in
3694 * STA role). TODO: make it better.
3695 */
3696 if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3697 ret = wl12xx_croc(wl, wl->dev_role_id);
3698 if (ret < 0)
3699 goto out;
3700
3701 ret = wl12xx_cmd_role_stop_dev(wl);
3702 if (ret < 0)
3703 goto out;
3704 }
Eliad Peller05dba352011-08-23 16:37:01 +03003705
3706 /* If we want to go in PSM but we're not there yet */
3707 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3708 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
3709 enum wl1271_cmd_ps_mode mode;
3710
3711 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003712 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003713 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003714 true);
3715 if (ret < 0)
3716 goto out;
3717 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003718 }
3719
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003720 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003721 if (sta_exists) {
3722 if ((changed & BSS_CHANGED_HT) &&
3723 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003724 ret = wl1271_acx_set_ht_capabilities(wl,
3725 &sta_ht_cap,
3726 true,
3727 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003728 if (ret < 0) {
3729 wl1271_warning("Set ht cap true failed %d",
3730 ret);
3731 goto out;
3732 }
3733 }
3734 /* handle new association without HT and disassociation */
3735 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003736 ret = wl1271_acx_set_ht_capabilities(wl,
3737 &sta_ht_cap,
3738 false,
3739 wl->sta_hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003740 if (ret < 0) {
3741 wl1271_warning("Set ht cap false failed %d",
3742 ret);
3743 goto out;
3744 }
3745 }
3746 }
3747
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003748 /* Handle HT information change. Done after join. */
3749 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003750 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003751 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003752 bss_conf->ht_operation_mode);
3753 if (ret < 0) {
3754 wl1271_warning("Set ht information failed %d", ret);
3755 goto out;
3756 }
3757 }
3758
Arik Nemtsove78a2872010-10-16 19:07:21 +02003759out:
3760 return;
3761}
3762
3763static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3764 struct ieee80211_vif *vif,
3765 struct ieee80211_bss_conf *bss_conf,
3766 u32 changed)
3767{
3768 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003769 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3770 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003771 int ret;
3772
3773 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3774 (int)changed);
3775
3776 mutex_lock(&wl->mutex);
3777
3778 if (unlikely(wl->state == WL1271_STATE_OFF))
3779 goto out;
3780
Ido Yariva6208652011-03-01 15:14:41 +02003781 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003782 if (ret < 0)
3783 goto out;
3784
3785 if (is_ap)
3786 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3787 else
3788 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3789
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003790 wl1271_ps_elp_sleep(wl);
3791
3792out:
3793 mutex_unlock(&wl->mutex);
3794}
3795
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003796static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3797 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003798 const struct ieee80211_tx_queue_params *params)
3799{
3800 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003801 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003802 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003803 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003804
3805 mutex_lock(&wl->mutex);
3806
3807 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3808
Kalle Valo4695dc92010-03-18 12:26:38 +02003809 if (params->uapsd)
3810 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3811 else
3812 ps_scheme = CONF_PS_SCHEME_LEGACY;
3813
Arik Nemtsov488fc542010-10-16 20:33:45 +02003814 if (wl->state == WL1271_STATE_OFF) {
3815 /*
3816 * If the state is off, the parameters will be recorded and
3817 * configured on init. This happens in AP-mode.
3818 */
3819 struct conf_tx_ac_category *conf_ac =
3820 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3821 struct conf_tx_tid *conf_tid =
3822 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3823
3824 conf_ac->ac = wl1271_tx_get_queue(queue);
3825 conf_ac->cw_min = (u8)params->cw_min;
3826 conf_ac->cw_max = params->cw_max;
3827 conf_ac->aifsn = params->aifs;
3828 conf_ac->tx_op_limit = params->txop << 5;
3829
3830 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3831 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3832 conf_tid->tsid = wl1271_tx_get_queue(queue);
3833 conf_tid->ps_scheme = ps_scheme;
3834 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3835 conf_tid->apsd_conf[0] = 0;
3836 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003837 goto out;
3838 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003839
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003840 ret = wl1271_ps_elp_wakeup(wl);
3841 if (ret < 0)
3842 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003843
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003844 /*
3845 * the txop is confed in units of 32us by the mac80211,
3846 * we need us
3847 */
Eliad Peller0603d892011-10-05 11:55:51 +02003848 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003849 params->cw_min, params->cw_max,
3850 params->aifs, params->txop << 5);
3851 if (ret < 0)
3852 goto out_sleep;
3853
Eliad Peller0603d892011-10-05 11:55:51 +02003854 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003855 CONF_CHANNEL_TYPE_EDCF,
3856 wl1271_tx_get_queue(queue),
3857 ps_scheme, CONF_ACK_POLICY_LEGACY,
3858 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003859
3860out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003861 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003862
3863out:
3864 mutex_unlock(&wl->mutex);
3865
3866 return ret;
3867}
3868
Eliad Peller37a41b42011-09-21 14:06:11 +03003869static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
3870 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003871{
3872
3873 struct wl1271 *wl = hw->priv;
3874 u64 mactime = ULLONG_MAX;
3875 int ret;
3876
3877 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3878
3879 mutex_lock(&wl->mutex);
3880
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003881 if (unlikely(wl->state == WL1271_STATE_OFF))
3882 goto out;
3883
Ido Yariva6208652011-03-01 15:14:41 +02003884 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003885 if (ret < 0)
3886 goto out;
3887
3888 ret = wl1271_acx_tsf_info(wl, &mactime);
3889 if (ret < 0)
3890 goto out_sleep;
3891
3892out_sleep:
3893 wl1271_ps_elp_sleep(wl);
3894
3895out:
3896 mutex_unlock(&wl->mutex);
3897 return mactime;
3898}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003899
John W. Linvilleece550d2010-07-28 16:41:06 -04003900static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3901 struct survey_info *survey)
3902{
3903 struct wl1271 *wl = hw->priv;
3904 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003905
John W. Linvilleece550d2010-07-28 16:41:06 -04003906 if (idx != 0)
3907 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003908
John W. Linvilleece550d2010-07-28 16:41:06 -04003909 survey->channel = conf->channel;
3910 survey->filled = SURVEY_INFO_NOISE_DBM;
3911 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003912
John W. Linvilleece550d2010-07-28 16:41:06 -04003913 return 0;
3914}
3915
Arik Nemtsov409622e2011-02-23 00:22:29 +02003916static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003917 struct ieee80211_sta *sta,
3918 u8 *hlid)
3919{
3920 struct wl1271_station *wl_sta;
3921 int id;
3922
3923 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3924 if (id >= AP_MAX_STATIONS) {
3925 wl1271_warning("could not allocate HLID - too much stations");
3926 return -EBUSY;
3927 }
3928
3929 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsov04216da2011-08-14 13:17:38 +03003930 set_bit(id, wl->ap_hlid_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003931 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3932 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003933 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03003934 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003935 return 0;
3936}
3937
Arik Nemtsovf1acea92011-08-25 12:43:17 +03003938void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003939{
3940 int id = hlid - WL1271_AP_STA_HLID_START;
3941
Arik Nemtsovf1acea92011-08-25 12:43:17 +03003942 if (hlid < WL1271_AP_STA_HLID_START)
3943 return;
3944
3945 if (!test_bit(id, wl->ap_hlid_map))
Arik Nemtsov409622e2011-02-23 00:22:29 +02003946 return;
3947
Arik Nemtsov04216da2011-08-14 13:17:38 +03003948 clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003949 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003950 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003951 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003952 __clear_bit(hlid, &wl->ap_ps_map);
3953 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +03003954 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003955}
3956
3957static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3958 struct ieee80211_vif *vif,
3959 struct ieee80211_sta *sta)
3960{
3961 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003962 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003963 int ret = 0;
3964 u8 hlid;
3965
3966 mutex_lock(&wl->mutex);
3967
3968 if (unlikely(wl->state == WL1271_STATE_OFF))
3969 goto out;
3970
Eliad Peller536129c2011-10-05 11:55:45 +02003971 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003972 goto out;
3973
3974 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3975
Arik Nemtsov409622e2011-02-23 00:22:29 +02003976 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003977 if (ret < 0)
3978 goto out;
3979
Ido Yariva6208652011-03-01 15:14:41 +02003980 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003981 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003982 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003983
Eliad Pellerc690ec82011-08-14 13:17:07 +03003984 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003985 if (ret < 0)
3986 goto out_sleep;
3987
Eliad Pellerb67476e2011-08-14 13:17:23 +03003988 ret = wl12xx_cmd_set_peer_state(wl, hlid);
3989 if (ret < 0)
3990 goto out_sleep;
3991
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003992 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
3993 if (ret < 0)
3994 goto out_sleep;
3995
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003996out_sleep:
3997 wl1271_ps_elp_sleep(wl);
3998
Arik Nemtsov409622e2011-02-23 00:22:29 +02003999out_free_sta:
4000 if (ret < 0)
4001 wl1271_free_sta(wl, hlid);
4002
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004003out:
4004 mutex_unlock(&wl->mutex);
4005 return ret;
4006}
4007
4008static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4009 struct ieee80211_vif *vif,
4010 struct ieee80211_sta *sta)
4011{
4012 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004013 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004014 struct wl1271_station *wl_sta;
4015 int ret = 0, id;
4016
4017 mutex_lock(&wl->mutex);
4018
4019 if (unlikely(wl->state == WL1271_STATE_OFF))
4020 goto out;
4021
Eliad Peller536129c2011-10-05 11:55:45 +02004022 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004023 goto out;
4024
4025 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4026
4027 wl_sta = (struct wl1271_station *)sta->drv_priv;
4028 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
4029 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
4030 goto out;
4031
Ido Yariva6208652011-03-01 15:14:41 +02004032 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004033 if (ret < 0)
4034 goto out;
4035
Eliad Pellerc690ec82011-08-14 13:17:07 +03004036 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004037 if (ret < 0)
4038 goto out_sleep;
4039
Arik Nemtsov409622e2011-02-23 00:22:29 +02004040 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004041
4042out_sleep:
4043 wl1271_ps_elp_sleep(wl);
4044
4045out:
4046 mutex_unlock(&wl->mutex);
4047 return ret;
4048}
4049
Luciano Coelho4623ec72011-03-21 19:26:41 +02004050static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4051 struct ieee80211_vif *vif,
4052 enum ieee80211_ampdu_mlme_action action,
4053 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4054 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004055{
4056 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004057 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004058 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004059 u8 hlid, *ba_bitmap;
4060
4061 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4062 tid);
4063
4064 /* sanity check - the fields in FW are only 8bits wide */
4065 if (WARN_ON(tid > 0xFF))
4066 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004067
4068 mutex_lock(&wl->mutex);
4069
4070 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4071 ret = -EAGAIN;
4072 goto out;
4073 }
4074
Eliad Peller536129c2011-10-05 11:55:45 +02004075 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004076 hlid = wl->sta_hlid;
4077 ba_bitmap = &wl->ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004078 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004079 struct wl1271_station *wl_sta;
4080
4081 wl_sta = (struct wl1271_station *)sta->drv_priv;
4082 hlid = wl_sta->hlid;
4083 ba_bitmap = &wl->links[hlid].ba_bitmap;
4084 } else {
4085 ret = -EINVAL;
4086 goto out;
4087 }
4088
Ido Yariva6208652011-03-01 15:14:41 +02004089 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004090 if (ret < 0)
4091 goto out;
4092
Shahar Levi70559a02011-05-22 16:10:22 +03004093 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4094 tid, action);
4095
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004096 switch (action) {
4097 case IEEE80211_AMPDU_RX_START:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004098 if (!wl->ba_support || !wl->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004099 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004100 break;
4101 }
4102
4103 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4104 ret = -EBUSY;
4105 wl1271_error("exceeded max RX BA sessions");
4106 break;
4107 }
4108
4109 if (*ba_bitmap & BIT(tid)) {
4110 ret = -EINVAL;
4111 wl1271_error("cannot enable RX BA session on active "
4112 "tid: %d", tid);
4113 break;
4114 }
4115
4116 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4117 hlid);
4118 if (!ret) {
4119 *ba_bitmap |= BIT(tid);
4120 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004121 }
4122 break;
4123
4124 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004125 if (!(*ba_bitmap & BIT(tid))) {
4126 ret = -EINVAL;
4127 wl1271_error("no active RX BA session on tid: %d",
4128 tid);
4129 break;
4130 }
4131
4132 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4133 hlid);
4134 if (!ret) {
4135 *ba_bitmap &= ~BIT(tid);
4136 wl->ba_rx_session_count--;
4137 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004138 break;
4139
4140 /*
4141 * The BA initiator session management in FW independently.
4142 * Falling break here on purpose for all TX APDU commands.
4143 */
4144 case IEEE80211_AMPDU_TX_START:
4145 case IEEE80211_AMPDU_TX_STOP:
4146 case IEEE80211_AMPDU_TX_OPERATIONAL:
4147 ret = -EINVAL;
4148 break;
4149
4150 default:
4151 wl1271_error("Incorrect ampdu action id=%x\n", action);
4152 ret = -EINVAL;
4153 }
4154
4155 wl1271_ps_elp_sleep(wl);
4156
4157out:
4158 mutex_unlock(&wl->mutex);
4159
4160 return ret;
4161}
4162
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004163static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4164 struct ieee80211_vif *vif,
4165 const struct cfg80211_bitrate_mask *mask)
4166{
4167 struct wl1271 *wl = hw->priv;
4168 int i;
4169
4170 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4171 mask->control[NL80211_BAND_2GHZ].legacy,
4172 mask->control[NL80211_BAND_5GHZ].legacy);
4173
4174 mutex_lock(&wl->mutex);
4175
4176 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
4177 wl->bitrate_masks[i] =
4178 wl1271_tx_enabled_rates_get(wl,
4179 mask->control[i].legacy,
4180 i);
4181 mutex_unlock(&wl->mutex);
4182
4183 return 0;
4184}
4185
Shahar Levi6d158ff2011-09-08 13:01:33 +03004186static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4187 struct ieee80211_channel_switch *ch_switch)
4188{
4189 struct wl1271 *wl = hw->priv;
4190 int ret;
4191
4192 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4193
4194 mutex_lock(&wl->mutex);
4195
4196 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4197 mutex_unlock(&wl->mutex);
4198 ieee80211_chswitch_done(wl->vif, false);
4199 return;
4200 }
4201
4202 ret = wl1271_ps_elp_wakeup(wl);
4203 if (ret < 0)
4204 goto out;
4205
4206 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
4207
4208 if (!ret)
4209 set_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags);
4210
4211 wl1271_ps_elp_sleep(wl);
4212
4213out:
4214 mutex_unlock(&wl->mutex);
4215}
4216
Arik Nemtsov33437892011-04-26 23:35:39 +03004217static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4218{
4219 struct wl1271 *wl = hw->priv;
4220 bool ret = false;
4221
4222 mutex_lock(&wl->mutex);
4223
4224 if (unlikely(wl->state == WL1271_STATE_OFF))
4225 goto out;
4226
4227 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004228 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004229out:
4230 mutex_unlock(&wl->mutex);
4231
4232 return ret;
4233}
4234
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004235/* can't be const, mac80211 writes to this */
4236static struct ieee80211_rate wl1271_rates[] = {
4237 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004238 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4239 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004240 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004241 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4242 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004243 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4244 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004245 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4246 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004247 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4248 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004249 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4250 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004251 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4252 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004253 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4254 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004255 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004256 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4257 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004258 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004259 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4260 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004261 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004262 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4263 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004264 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004265 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4266 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004267 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004268 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4269 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004270 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004271 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4272 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004273 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004274 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4275 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004276};
4277
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004278/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004279static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004280 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004281 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004282 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4283 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4284 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004285 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004286 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4287 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4288 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004289 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004290 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4291 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4292 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004293 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004294};
4295
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004296/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004297static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004298 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004299 7, /* CONF_HW_RXTX_RATE_MCS7 */
4300 6, /* CONF_HW_RXTX_RATE_MCS6 */
4301 5, /* CONF_HW_RXTX_RATE_MCS5 */
4302 4, /* CONF_HW_RXTX_RATE_MCS4 */
4303 3, /* CONF_HW_RXTX_RATE_MCS3 */
4304 2, /* CONF_HW_RXTX_RATE_MCS2 */
4305 1, /* CONF_HW_RXTX_RATE_MCS1 */
4306 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004307
4308 11, /* CONF_HW_RXTX_RATE_54 */
4309 10, /* CONF_HW_RXTX_RATE_48 */
4310 9, /* CONF_HW_RXTX_RATE_36 */
4311 8, /* CONF_HW_RXTX_RATE_24 */
4312
4313 /* TI-specific rate */
4314 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4315
4316 7, /* CONF_HW_RXTX_RATE_18 */
4317 6, /* CONF_HW_RXTX_RATE_12 */
4318 3, /* CONF_HW_RXTX_RATE_11 */
4319 5, /* CONF_HW_RXTX_RATE_9 */
4320 4, /* CONF_HW_RXTX_RATE_6 */
4321 2, /* CONF_HW_RXTX_RATE_5_5 */
4322 1, /* CONF_HW_RXTX_RATE_2 */
4323 0 /* CONF_HW_RXTX_RATE_1 */
4324};
4325
Shahar Levie8b03a22010-10-13 16:09:39 +02004326/* 11n STA capabilities */
4327#define HW_RX_HIGHEST_RATE 72
4328
Shahar Levi00d20102010-11-08 11:20:10 +00004329#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004330 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4331 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004332 .ht_supported = true, \
4333 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4334 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4335 .mcs = { \
4336 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4337 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4338 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4339 }, \
4340}
4341
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004342/* can't be const, mac80211 writes to this */
4343static struct ieee80211_supported_band wl1271_band_2ghz = {
4344 .channels = wl1271_channels,
4345 .n_channels = ARRAY_SIZE(wl1271_channels),
4346 .bitrates = wl1271_rates,
4347 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004348 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004349};
4350
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004351/* 5 GHz data rates for WL1273 */
4352static struct ieee80211_rate wl1271_rates_5ghz[] = {
4353 { .bitrate = 60,
4354 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4355 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4356 { .bitrate = 90,
4357 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4358 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4359 { .bitrate = 120,
4360 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4361 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4362 { .bitrate = 180,
4363 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4364 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4365 { .bitrate = 240,
4366 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4367 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4368 { .bitrate = 360,
4369 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4370 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4371 { .bitrate = 480,
4372 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4373 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4374 { .bitrate = 540,
4375 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4376 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4377};
4378
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004379/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004380static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004381 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4382 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4383 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4384 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4385 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4386 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4387 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4388 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4389 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4390 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4391 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4392 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4393 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4394 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4395 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4396 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4397 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4398 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4399 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4400 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4401 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4402 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4403 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4404 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4405 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4406 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4407 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4408 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4409 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4410 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4411 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4412 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4413 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4414 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004415};
4416
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004417/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004418static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004419 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004420 7, /* CONF_HW_RXTX_RATE_MCS7 */
4421 6, /* CONF_HW_RXTX_RATE_MCS6 */
4422 5, /* CONF_HW_RXTX_RATE_MCS5 */
4423 4, /* CONF_HW_RXTX_RATE_MCS4 */
4424 3, /* CONF_HW_RXTX_RATE_MCS3 */
4425 2, /* CONF_HW_RXTX_RATE_MCS2 */
4426 1, /* CONF_HW_RXTX_RATE_MCS1 */
4427 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004428
4429 7, /* CONF_HW_RXTX_RATE_54 */
4430 6, /* CONF_HW_RXTX_RATE_48 */
4431 5, /* CONF_HW_RXTX_RATE_36 */
4432 4, /* CONF_HW_RXTX_RATE_24 */
4433
4434 /* TI-specific rate */
4435 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4436
4437 3, /* CONF_HW_RXTX_RATE_18 */
4438 2, /* CONF_HW_RXTX_RATE_12 */
4439 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4440 1, /* CONF_HW_RXTX_RATE_9 */
4441 0, /* CONF_HW_RXTX_RATE_6 */
4442 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4443 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4444 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4445};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004446
4447static struct ieee80211_supported_band wl1271_band_5ghz = {
4448 .channels = wl1271_channels_5ghz,
4449 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4450 .bitrates = wl1271_rates_5ghz,
4451 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004452 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004453};
4454
Tobias Klausera0ea9492010-05-20 10:38:11 +02004455static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004456 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4457 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4458};
4459
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004460static const struct ieee80211_ops wl1271_ops = {
4461 .start = wl1271_op_start,
4462 .stop = wl1271_op_stop,
4463 .add_interface = wl1271_op_add_interface,
4464 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004465#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004466 .suspend = wl1271_op_suspend,
4467 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004468#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004469 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004470 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004471 .configure_filter = wl1271_op_configure_filter,
4472 .tx = wl1271_op_tx,
4473 .set_key = wl1271_op_set_key,
4474 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004475 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004476 .sched_scan_start = wl1271_op_sched_scan_start,
4477 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004478 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004479 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004480 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004481 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004482 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004483 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004484 .sta_add = wl1271_op_sta_add,
4485 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004486 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004487 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004488 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004489 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004490 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004491};
4492
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004493
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004494u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004495{
4496 u8 idx;
4497
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004498 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004499
4500 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4501 wl1271_error("Illegal RX rate from HW: %d", rate);
4502 return 0;
4503 }
4504
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004505 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004506 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4507 wl1271_error("Unsupported RX rate from HW: %d", rate);
4508 return 0;
4509 }
4510
4511 return idx;
4512}
4513
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004514static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4515 struct device_attribute *attr,
4516 char *buf)
4517{
4518 struct wl1271 *wl = dev_get_drvdata(dev);
4519 ssize_t len;
4520
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004521 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004522
4523 mutex_lock(&wl->mutex);
4524 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4525 wl->sg_enabled);
4526 mutex_unlock(&wl->mutex);
4527
4528 return len;
4529
4530}
4531
4532static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4533 struct device_attribute *attr,
4534 const char *buf, size_t count)
4535{
4536 struct wl1271 *wl = dev_get_drvdata(dev);
4537 unsigned long res;
4538 int ret;
4539
Luciano Coelho6277ed62011-04-01 17:49:54 +03004540 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004541 if (ret < 0) {
4542 wl1271_warning("incorrect value written to bt_coex_mode");
4543 return count;
4544 }
4545
4546 mutex_lock(&wl->mutex);
4547
4548 res = !!res;
4549
4550 if (res == wl->sg_enabled)
4551 goto out;
4552
4553 wl->sg_enabled = res;
4554
4555 if (wl->state == WL1271_STATE_OFF)
4556 goto out;
4557
Ido Yariva6208652011-03-01 15:14:41 +02004558 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004559 if (ret < 0)
4560 goto out;
4561
4562 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4563 wl1271_ps_elp_sleep(wl);
4564
4565 out:
4566 mutex_unlock(&wl->mutex);
4567 return count;
4568}
4569
4570static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4571 wl1271_sysfs_show_bt_coex_state,
4572 wl1271_sysfs_store_bt_coex_state);
4573
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004574static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4575 struct device_attribute *attr,
4576 char *buf)
4577{
4578 struct wl1271 *wl = dev_get_drvdata(dev);
4579 ssize_t len;
4580
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004581 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004582
4583 mutex_lock(&wl->mutex);
4584 if (wl->hw_pg_ver >= 0)
4585 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4586 else
4587 len = snprintf(buf, len, "n/a\n");
4588 mutex_unlock(&wl->mutex);
4589
4590 return len;
4591}
4592
Gery Kahn6f07b722011-07-18 14:21:49 +03004593static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004594 wl1271_sysfs_show_hw_pg_ver, NULL);
4595
Ido Yariv95dac04f2011-06-06 14:57:06 +03004596static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4597 struct bin_attribute *bin_attr,
4598 char *buffer, loff_t pos, size_t count)
4599{
4600 struct device *dev = container_of(kobj, struct device, kobj);
4601 struct wl1271 *wl = dev_get_drvdata(dev);
4602 ssize_t len;
4603 int ret;
4604
4605 ret = mutex_lock_interruptible(&wl->mutex);
4606 if (ret < 0)
4607 return -ERESTARTSYS;
4608
4609 /* Let only one thread read the log at a time, blocking others */
4610 while (wl->fwlog_size == 0) {
4611 DEFINE_WAIT(wait);
4612
4613 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4614 &wait,
4615 TASK_INTERRUPTIBLE);
4616
4617 if (wl->fwlog_size != 0) {
4618 finish_wait(&wl->fwlog_waitq, &wait);
4619 break;
4620 }
4621
4622 mutex_unlock(&wl->mutex);
4623
4624 schedule();
4625 finish_wait(&wl->fwlog_waitq, &wait);
4626
4627 if (signal_pending(current))
4628 return -ERESTARTSYS;
4629
4630 ret = mutex_lock_interruptible(&wl->mutex);
4631 if (ret < 0)
4632 return -ERESTARTSYS;
4633 }
4634
4635 /* Check if the fwlog is still valid */
4636 if (wl->fwlog_size < 0) {
4637 mutex_unlock(&wl->mutex);
4638 return 0;
4639 }
4640
4641 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4642 len = min(count, (size_t)wl->fwlog_size);
4643 wl->fwlog_size -= len;
4644 memcpy(buffer, wl->fwlog, len);
4645
4646 /* Make room for new messages */
4647 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4648
4649 mutex_unlock(&wl->mutex);
4650
4651 return len;
4652}
4653
4654static struct bin_attribute fwlog_attr = {
4655 .attr = {.name = "fwlog", .mode = S_IRUSR},
4656 .read = wl1271_sysfs_read_fwlog,
4657};
4658
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004659int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004660{
4661 int ret;
4662
4663 if (wl->mac80211_registered)
4664 return 0;
4665
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004666 ret = wl1271_fetch_nvs(wl);
4667 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004668 /* NOTE: The wl->nvs->nvs element must be first, in
4669 * order to simplify the casting, we assume it is at
4670 * the beginning of the wl->nvs structure.
4671 */
4672 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004673
4674 wl->mac_addr[0] = nvs_ptr[11];
4675 wl->mac_addr[1] = nvs_ptr[10];
4676 wl->mac_addr[2] = nvs_ptr[6];
4677 wl->mac_addr[3] = nvs_ptr[5];
4678 wl->mac_addr[4] = nvs_ptr[4];
4679 wl->mac_addr[5] = nvs_ptr[3];
4680 }
4681
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004682 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4683
4684 ret = ieee80211_register_hw(wl->hw);
4685 if (ret < 0) {
4686 wl1271_error("unable to register mac80211 hw: %d", ret);
4687 return ret;
4688 }
4689
4690 wl->mac80211_registered = true;
4691
Eliad Pellerd60080a2010-11-24 12:53:16 +02004692 wl1271_debugfs_init(wl);
4693
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004694 register_netdevice_notifier(&wl1271_dev_notifier);
4695
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004696 wl1271_notice("loaded");
4697
4698 return 0;
4699}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004700EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004701
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004702void wl1271_unregister_hw(struct wl1271 *wl)
4703{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004704 if (wl->state == WL1271_STATE_PLT)
4705 __wl1271_plt_stop(wl);
4706
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004707 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004708 ieee80211_unregister_hw(wl->hw);
4709 wl->mac80211_registered = false;
4710
4711}
4712EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4713
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004714int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004715{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004716 static const u32 cipher_suites[] = {
4717 WLAN_CIPHER_SUITE_WEP40,
4718 WLAN_CIPHER_SUITE_WEP104,
4719 WLAN_CIPHER_SUITE_TKIP,
4720 WLAN_CIPHER_SUITE_CCMP,
4721 WL1271_CIPHER_SUITE_GEM,
4722 };
4723
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004724 /* The tx descriptor buffer and the TKIP space. */
4725 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4726 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004727
4728 /* unit us */
4729 /* FIXME: find a proper value */
4730 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004731 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004732
4733 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004734 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004735 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004736 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004737 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004738 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004739 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004740 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004741 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004742 IEEE80211_HW_AP_LINK_PS |
4743 IEEE80211_HW_AMPDU_AGGREGATION |
4744 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004745
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004746 wl->hw->wiphy->cipher_suites = cipher_suites;
4747 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4748
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004749 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004750 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4751 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004752 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004753 wl->hw->wiphy->max_sched_scan_ssids = 16;
4754 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004755 /*
4756 * Maximum length of elements in scanning probe request templates
4757 * should be the maximum length possible for a template, without
4758 * the IEEE80211 header of the template
4759 */
Eliad Peller154037d2011-08-14 13:17:12 +03004760 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004761 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004762
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004763 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4764 sizeof(struct ieee80211_header);
4765
Eliad Peller1ec23f72011-08-25 14:26:54 +03004766 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4767
Luciano Coelho4a31c112011-03-21 23:16:14 +02004768 /* make sure all our channels fit in the scanned_ch bitmask */
4769 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4770 ARRAY_SIZE(wl1271_channels_5ghz) >
4771 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004772 /*
4773 * We keep local copies of the band structs because we need to
4774 * modify them on a per-device basis.
4775 */
4776 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4777 sizeof(wl1271_band_2ghz));
4778 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4779 sizeof(wl1271_band_5ghz));
4780
4781 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4782 &wl->bands[IEEE80211_BAND_2GHZ];
4783 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4784 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004785
Kalle Valo12bd8942010-03-18 12:26:33 +02004786 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004787 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004788
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004789 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4790
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004791 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004792
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004793 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004794 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004795
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004796 wl->hw->max_rx_aggregation_subframes = 8;
4797
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004798 return 0;
4799}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004800EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004801
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004802#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004803
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004804struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004805{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004806 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004807 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004808 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004809 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004810 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004811
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004812 BUILD_BUG_ON(AP_MAX_LINKS > WL12XX_MAX_LINKS);
4813
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004814 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4815 if (!hw) {
4816 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004817 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004818 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004819 }
4820
Julia Lawall929ebd32010-05-15 23:16:39 +02004821 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004822 if (!plat_dev) {
4823 wl1271_error("could not allocate platform_device");
4824 ret = -ENOMEM;
4825 goto err_plat_alloc;
4826 }
4827
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004828 wl = hw->priv;
4829 memset(wl, 0, sizeof(*wl));
4830
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004831 INIT_LIST_HEAD(&wl->list);
4832
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004833 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004834 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004835
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004836 for (i = 0; i < NUM_TX_QUEUES; i++)
4837 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004838
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004839 for (i = 0; i < NUM_TX_QUEUES; i++)
4840 for (j = 0; j < AP_MAX_LINKS; j++)
4841 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4842
Ido Yariva6208652011-03-01 15:14:41 +02004843 skb_queue_head_init(&wl->deferred_rx_queue);
4844 skb_queue_head_init(&wl->deferred_tx_queue);
4845
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004846 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004847 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004848 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004849 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4850 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4851 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004852 INIT_WORK(&wl->rx_streaming_enable_work,
4853 wl1271_rx_streaming_enable_work);
4854 INIT_WORK(&wl->rx_streaming_disable_work,
4855 wl1271_rx_streaming_disable_work);
4856
Eliad Peller92ef8962011-06-07 12:50:46 +03004857 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4858 if (!wl->freezable_wq) {
4859 ret = -ENOMEM;
4860 goto err_hw;
4861 }
4862
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004863 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004864 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004865 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004866 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004867 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004868 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004869 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004870 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004871 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004872 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004873 wl->hw_pg_ver = -1;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004874 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004875 wl->ap_ps_map = 0;
4876 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004877 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004878 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004879 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004880 wl->tx_security_seq = 0;
4881 wl->tx_security_last_seq_lsb = 0;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03004882 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004883 wl->system_hlid = WL12XX_SYSTEM_HLID;
Eliad Peller7f0979882011-08-14 13:17:06 +03004884 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004885 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4886 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsov712e9bf2011-08-14 13:17:20 +03004887 wl->session_counter = 0;
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03004888 wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
4889 wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
Arik Nemtsovda032092011-08-25 12:43:15 +03004890 wl->active_sta_count = 0;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004891 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4892 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004893 wl->fwlog_size = 0;
4894 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004895
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004896 /* The system link is always allocated */
4897 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4898
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004899 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004900 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004901 wl->tx_frames[i] = NULL;
4902
4903 spin_lock_init(&wl->wl_lock);
4904
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004905 wl->state = WL1271_STATE_OFF;
4906 mutex_init(&wl->mutex);
4907
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004908 /* Apply default driver configuration. */
4909 wl1271_conf_init(wl);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004910 wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
4911 wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004912
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004913 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4914 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4915 if (!wl->aggr_buf) {
4916 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004917 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004918 }
4919
Ido Yariv990f5de2011-03-31 10:06:59 +02004920 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4921 if (!wl->dummy_packet) {
4922 ret = -ENOMEM;
4923 goto err_aggr;
4924 }
4925
Ido Yariv95dac04f2011-06-06 14:57:06 +03004926 /* Allocate one page for the FW log */
4927 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4928 if (!wl->fwlog) {
4929 ret = -ENOMEM;
4930 goto err_dummy_packet;
4931 }
4932
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004933 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004934 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004935 if (ret) {
4936 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004937 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004938 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004939 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004940
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004941 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004942 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004943 if (ret < 0) {
4944 wl1271_error("failed to create sysfs file bt_coex_state");
4945 goto err_platform;
4946 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004947
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004948 /* Create sysfs file to get HW PG version */
4949 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4950 if (ret < 0) {
4951 wl1271_error("failed to create sysfs file hw_pg_ver");
4952 goto err_bt_coex_state;
4953 }
4954
Ido Yariv95dac04f2011-06-06 14:57:06 +03004955 /* Create sysfs file for the FW log */
4956 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4957 if (ret < 0) {
4958 wl1271_error("failed to create sysfs file fwlog");
4959 goto err_hw_pg_ver;
4960 }
4961
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004962 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004963
Ido Yariv95dac04f2011-06-06 14:57:06 +03004964err_hw_pg_ver:
4965 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4966
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004967err_bt_coex_state:
4968 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4969
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004970err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004971 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004972
Ido Yariv95dac04f2011-06-06 14:57:06 +03004973err_fwlog:
4974 free_page((unsigned long)wl->fwlog);
4975
Ido Yariv990f5de2011-03-31 10:06:59 +02004976err_dummy_packet:
4977 dev_kfree_skb(wl->dummy_packet);
4978
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004979err_aggr:
4980 free_pages((unsigned long)wl->aggr_buf, order);
4981
Eliad Peller92ef8962011-06-07 12:50:46 +03004982err_wq:
4983 destroy_workqueue(wl->freezable_wq);
4984
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004985err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004986 wl1271_debugfs_exit(wl);
4987 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004988
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004989err_plat_alloc:
4990 ieee80211_free_hw(hw);
4991
4992err_hw_alloc:
4993
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004994 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004995}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004996EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004997
4998int wl1271_free_hw(struct wl1271 *wl)
4999{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005000 /* Unblock any fwlog readers */
5001 mutex_lock(&wl->mutex);
5002 wl->fwlog_size = -1;
5003 wake_up_interruptible_all(&wl->fwlog_waitq);
5004 mutex_unlock(&wl->mutex);
5005
5006 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005007
5008 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5009
5010 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005011 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005012 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005013 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005014 free_pages((unsigned long)wl->aggr_buf,
5015 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005016 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005017
5018 wl1271_debugfs_exit(wl);
5019
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005020 vfree(wl->fw);
5021 wl->fw = NULL;
5022 kfree(wl->nvs);
5023 wl->nvs = NULL;
5024
5025 kfree(wl->fw_status);
5026 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005027 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005028
5029 ieee80211_free_hw(wl->hw);
5030
5031 return 0;
5032}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005033EXPORT_SYMBOL_GPL(wl1271_free_hw);
5034
Guy Eilam491bbd62011-01-12 10:33:29 +01005035u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005036EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005037module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005038MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5039
Ido Yariv95dac04f2011-06-06 14:57:06 +03005040module_param_named(fwlog, fwlog_param, charp, 0);
5041MODULE_PARM_DESC(keymap,
5042 "FW logger options: continuous, ondemand, dbgpins or disable");
5043
Eliad Peller2a5bff02011-08-25 18:10:59 +03005044module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5045MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5046
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005047MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005048MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005049MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");