blob: 56d592398677b93d29b0034c40700a7bb29764d7 [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-Cohen958b20e2011-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);
Eliad Peller170d0e62011-10-05 11:56:06 +0200382static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
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 Peller154da672011-10-05 11:55:53 +0200415 ret = wl12xx_cmd_set_peer_state(wl, wlvif->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
Arik Nemtsovb622d992011-02-23 00:22:31 +0200781 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300782 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200783
784 /*
785 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300786 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200787 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300788 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200789 wl1271_ps_link_end(wl, hlid);
790
Arik Nemtsovda032092011-08-25 12:43:15 +0300791 /*
792 * Start high-level PS if the STA is asleep with enough blocks in FW.
793 * Make an exception if this is the only connected station. In this
794 * case FW-memory congestion is not a problem.
795 */
796 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200797 wl1271_ps_link_start(wl, hlid, true);
798}
799
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300800static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200801 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300802 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200803{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200804 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200805 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300806 u8 hlid, cnt;
807
808 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200809
810 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
811 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
812 wl1271_debug(DEBUG_PSM,
813 "link ps prev 0x%x cur 0x%x changed 0x%x",
814 wl->ap_fw_ps_map, cur_fw_ps_map,
815 wl->ap_fw_ps_map ^ cur_fw_ps_map);
816
817 wl->ap_fw_ps_map = cur_fw_ps_map;
818 }
819
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200820 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
821 lnk = &wl->links[hlid];
822 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200823
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200824 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
825 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200826
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200827 wl12xx_irq_ps_regulate_link(wl, hlid, lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200828 }
829}
830
Eliad Peller4d56ad92011-08-14 13:17:05 +0300831static void wl12xx_fw_status(struct wl1271 *wl,
832 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300833{
Eliad Peller536129c2011-10-05 11:55:45 +0200834 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
835 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200836 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200837 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300838 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300839 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300840
Eliad Peller4d56ad92011-08-14 13:17:05 +0300841 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200842
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300843 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
844 "drv_rx_counter = %d, tx_results_counter = %d)",
845 status->intr,
846 status->fw_rx_counter,
847 status->drv_rx_counter,
848 status->tx_results_counter);
849
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300850 for (i = 0; i < NUM_TX_QUEUES; i++) {
851 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300852 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300853 (status->tx_released_pkts[i] -
854 wl->tx_pkts_freed[i]) & 0xff;
855
856 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
857 }
858
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300859 /* prevent wrap-around in total blocks counter */
860 if (likely(wl->tx_blocks_freed <=
861 le32_to_cpu(status->total_released_blks)))
862 freed_blocks = le32_to_cpu(status->total_released_blks) -
863 wl->tx_blocks_freed;
864 else
865 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
866 le32_to_cpu(status->total_released_blks);
867
Eliad Peller4d56ad92011-08-14 13:17:05 +0300868 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200869
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300870 wl->tx_allocated_blocks -= freed_blocks;
871
Eliad Peller4d56ad92011-08-14 13:17:05 +0300872 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200873
Eliad Peller4d56ad92011-08-14 13:17:05 +0300874 /*
875 * The FW might change the total number of TX memblocks before
876 * we get a notification about blocks being released. Thus, the
877 * available blocks calculation might yield a temporary result
878 * which is lower than the actual available blocks. Keeping in
879 * mind that only blocks that were allocated can be moved from
880 * TX to RX, tx_blocks_available should never decrease here.
881 */
882 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
883 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300884
Ido Yariva5225502010-10-12 14:49:10 +0200885 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200886 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200887 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300888
Eliad Peller4d56ad92011-08-14 13:17:05 +0300889 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller536129c2011-10-05 11:55:45 +0200890 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200891 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller4d56ad92011-08-14 13:17:05 +0300892
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300893 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200894 getnstimeofday(&ts);
895 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
896 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300897}
898
Ido Yariva6208652011-03-01 15:14:41 +0200899static void wl1271_flush_deferred_work(struct wl1271 *wl)
900{
901 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200902
Ido Yariva6208652011-03-01 15:14:41 +0200903 /* Pass all received frames to the network stack */
904 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
905 ieee80211_rx_ni(wl->hw, skb);
906
907 /* Return sent skbs to the network stack */
908 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300909 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200910}
911
912static void wl1271_netstack_work(struct work_struct *work)
913{
914 struct wl1271 *wl =
915 container_of(work, struct wl1271, netstack_work);
916
917 do {
918 wl1271_flush_deferred_work(wl);
919 } while (skb_queue_len(&wl->deferred_rx_queue));
920}
921
922#define WL1271_IRQ_MAX_LOOPS 256
923
924irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300925{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300926 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300927 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200928 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200929 struct wl1271 *wl = (struct wl1271 *)cookie;
930 bool done = false;
931 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200932 unsigned long flags;
933
934 /* TX might be handled here, avoid redundant work */
935 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
936 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937
Ido Yariv341b7cd2011-03-31 10:07:01 +0200938 /*
939 * In case edge triggered interrupt must be used, we cannot iterate
940 * more than once without introducing race conditions with the hardirq.
941 */
942 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
943 loopcount = 1;
944
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945 mutex_lock(&wl->mutex);
946
947 wl1271_debug(DEBUG_IRQ, "IRQ work");
948
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200949 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300950 goto out;
951
Ido Yariva6208652011-03-01 15:14:41 +0200952 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300953 if (ret < 0)
954 goto out;
955
Ido Yariva6208652011-03-01 15:14:41 +0200956 while (!done && loopcount--) {
957 /*
958 * In order to avoid a race with the hardirq, clear the flag
959 * before acknowledging the chip. Since the mutex is held,
960 * wl1271_ps_elp_wakeup cannot be called concurrently.
961 */
962 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
963 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200964
Eliad Peller4d56ad92011-08-14 13:17:05 +0300965 wl12xx_fw_status(wl, wl->fw_status);
966 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200967 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200968 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200969 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200970 continue;
971 }
972
Eliad Pellerccc83b02010-10-27 14:09:57 +0200973 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
974 wl1271_error("watchdog interrupt received! "
975 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300976 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200977
978 /* restarting the chip. ignore any other interrupt. */
979 goto out;
980 }
981
Ido Yariva6208652011-03-01 15:14:41 +0200982 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200983 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
984
Eliad Peller4d56ad92011-08-14 13:17:05 +0300985 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200986
Ido Yariva5225502010-10-12 14:49:10 +0200987 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200988 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200989 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300990 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200991 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200992 /*
993 * In order to avoid starvation of the TX path,
994 * call the work function directly.
995 */
Eliad Peller536129c2011-10-05 11:55:45 +0200996 wl1271_tx_work_locked(wl, wl->vif);
Ido Yarivb07d4032011-03-01 15:14:43 +0200997 } else {
998 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200999 }
1000
Ido Yariv8aad2462011-03-01 15:14:38 +02001001 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001002 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +02001003 (wl->tx_results_count & 0xff))
1004 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001005
1006 /* Make sure the deferred queues don't get too long */
1007 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1008 skb_queue_len(&wl->deferred_rx_queue);
1009 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1010 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001011 }
1012
1013 if (intr & WL1271_ACX_INTR_EVENT_A) {
1014 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1015 wl1271_event_handle(wl, 0);
1016 }
1017
1018 if (intr & WL1271_ACX_INTR_EVENT_B) {
1019 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1020 wl1271_event_handle(wl, 1);
1021 }
1022
1023 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1024 wl1271_debug(DEBUG_IRQ,
1025 "WL1271_ACX_INTR_INIT_COMPLETE");
1026
1027 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1028 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029 }
1030
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031 wl1271_ps_elp_sleep(wl);
1032
1033out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001034 spin_lock_irqsave(&wl->wl_lock, flags);
1035 /* In case TX was not handled here, queue TX work */
1036 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1037 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001038 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001039 ieee80211_queue_work(wl->hw, &wl->tx_work);
1040 spin_unlock_irqrestore(&wl->wl_lock, flags);
1041
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001043
1044 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045}
Ido Yariva6208652011-03-01 15:14:41 +02001046EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048static int wl1271_fetch_firmware(struct wl1271 *wl)
1049{
1050 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001051 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052 int ret;
1053
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001054 if (wl->chip.id == CHIP_ID_1283_PG20)
1055 fw_name = WL128X_FW_NAME;
1056 else
1057 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001058
1059 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1060
1061 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062
1063 if (ret < 0) {
1064 wl1271_error("could not get firmware: %d", ret);
1065 return ret;
1066 }
1067
1068 if (fw->size % 4) {
1069 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1070 fw->size);
1071 ret = -EILSEQ;
1072 goto out;
1073 }
1074
Arik Nemtsov166d5042010-10-16 21:44:57 +02001075 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001076 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001077 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001078
1079 if (!wl->fw) {
1080 wl1271_error("could not allocate memory for the firmware");
1081 ret = -ENOMEM;
1082 goto out;
1083 }
1084
1085 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001086 ret = 0;
1087
1088out:
1089 release_firmware(fw);
1090
1091 return ret;
1092}
1093
1094static int wl1271_fetch_nvs(struct wl1271 *wl)
1095{
1096 const struct firmware *fw;
1097 int ret;
1098
Shahar Levi5aa42342011-03-06 16:32:07 +02001099 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001100
1101 if (ret < 0) {
1102 wl1271_error("could not get nvs file: %d", ret);
1103 return ret;
1104 }
1105
Shahar Levibc765bf2011-03-06 16:32:10 +02001106 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001107
1108 if (!wl->nvs) {
1109 wl1271_error("could not allocate memory for the nvs file");
1110 ret = -ENOMEM;
1111 goto out;
1112 }
1113
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001114 wl->nvs_len = fw->size;
1115
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001116out:
1117 release_firmware(fw);
1118
1119 return ret;
1120}
1121
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001122void wl12xx_queue_recovery_work(struct wl1271 *wl)
1123{
1124 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1125 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1126}
1127
Ido Yariv95dac04f2011-06-06 14:57:06 +03001128size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1129{
1130 size_t len = 0;
1131
1132 /* The FW log is a length-value list, find where the log end */
1133 while (len < maxlen) {
1134 if (memblock[len] == 0)
1135 break;
1136 if (len + memblock[len] + 1 > maxlen)
1137 break;
1138 len += memblock[len] + 1;
1139 }
1140
1141 /* Make sure we have enough room */
1142 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1143
1144 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1145 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1146 wl->fwlog_size += len;
1147
1148 return len;
1149}
1150
1151static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1152{
1153 u32 addr;
1154 u32 first_addr;
1155 u8 *block;
1156
1157 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1158 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1159 (wl->conf.fwlog.mem_blocks == 0))
1160 return;
1161
1162 wl1271_info("Reading FW panic log");
1163
1164 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1165 if (!block)
1166 return;
1167
1168 /*
1169 * Make sure the chip is awake and the logger isn't active.
1170 * This might fail if the firmware hanged.
1171 */
1172 if (!wl1271_ps_elp_wakeup(wl))
1173 wl12xx_cmd_stop_fwlog(wl);
1174
1175 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001176 wl12xx_fw_status(wl, wl->fw_status);
1177 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001178 if (!first_addr)
1179 goto out;
1180
1181 /* Traverse the memory blocks linked list */
1182 addr = first_addr;
1183 do {
1184 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1185 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1186 false);
1187
1188 /*
1189 * Memory blocks are linked to one another. The first 4 bytes
1190 * of each memory block hold the hardware address of the next
1191 * one. The last memory block points to the first one.
1192 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001193 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001194 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1195 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1196 break;
1197 } while (addr && (addr != first_addr));
1198
1199 wake_up_interruptible(&wl->fwlog_waitq);
1200
1201out:
1202 kfree(block);
1203}
1204
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001205static void wl1271_recovery_work(struct work_struct *work)
1206{
1207 struct wl1271 *wl =
1208 container_of(work, struct wl1271, recovery_work);
1209
1210 mutex_lock(&wl->mutex);
1211
1212 if (wl->state != WL1271_STATE_ON)
1213 goto out;
1214
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001215 /* Avoid a recursive recovery */
1216 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1217
Ido Yariv95dac04f2011-06-06 14:57:06 +03001218 wl12xx_read_fwlog_panic(wl);
1219
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001220 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1221 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001222
Eliad Peller2a5bff02011-08-25 18:10:59 +03001223 BUG_ON(bug_on_recovery);
1224
Oz Krakowskib992c682011-06-26 10:36:02 +03001225 /*
1226 * Advance security sequence number to overcome potential progress
1227 * in the firmware during recovery. This doens't hurt if the network is
1228 * not encrypted.
1229 */
1230 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1231 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1232 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1233
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001234 /* Prevent spurious TX during FW restart */
1235 ieee80211_stop_queues(wl->hw);
1236
Luciano Coelho33c2c062011-05-10 14:46:02 +03001237 if (wl->sched_scanning) {
1238 ieee80211_sched_scan_stopped(wl->hw);
1239 wl->sched_scanning = false;
1240 }
1241
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001242 /* reboot the chipset */
Eliad Peller536129c2011-10-05 11:55:45 +02001243 __wl1271_op_remove_interface(wl, wl->vif, false);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001244
1245 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1246
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001247 ieee80211_restart_hw(wl->hw);
1248
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001249 /*
1250 * Its safe to enable TX now - the queues are stopped after a request
1251 * to restart the HW.
1252 */
1253 ieee80211_wake_queues(wl->hw);
1254
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001255out:
1256 mutex_unlock(&wl->mutex);
1257}
1258
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001259static void wl1271_fw_wakeup(struct wl1271 *wl)
1260{
1261 u32 elp_reg;
1262
1263 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001264 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001265}
1266
1267static int wl1271_setup(struct wl1271 *wl)
1268{
1269 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1270 if (!wl->fw_status)
1271 return -ENOMEM;
1272
1273 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1274 if (!wl->tx_res_if) {
1275 kfree(wl->fw_status);
1276 return -ENOMEM;
1277 }
1278
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001279 return 0;
1280}
1281
1282static int wl1271_chip_wakeup(struct wl1271 *wl)
1283{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001284 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 int ret = 0;
1286
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001287 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001288 ret = wl1271_power_on(wl);
1289 if (ret < 0)
1290 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001292 wl1271_io_reset(wl);
1293 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294
1295 /* We don't need a real memory partition here, because we only want
1296 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001297 memset(&partition, 0, sizeof(partition));
1298 partition.reg.start = REGISTERS_BASE;
1299 partition.reg.size = REGISTERS_DOWN_SIZE;
1300 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301
1302 /* ELP module wake up */
1303 wl1271_fw_wakeup(wl);
1304
1305 /* whal_FwCtrl_BootSm() */
1306
1307 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001308 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001309
1310 /* 1. check if chip id is valid */
1311
1312 switch (wl->chip.id) {
1313 case CHIP_ID_1271_PG10:
1314 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1315 wl->chip.id);
1316
1317 ret = wl1271_setup(wl);
1318 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001319 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001320 break;
1321 case CHIP_ID_1271_PG20:
1322 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1323 wl->chip.id);
1324
1325 ret = wl1271_setup(wl);
1326 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001327 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001328 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001329 case CHIP_ID_1283_PG20:
1330 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1331 wl->chip.id);
1332
1333 ret = wl1271_setup(wl);
1334 if (ret < 0)
1335 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001336
Ido Yariv0da13da2011-03-31 10:06:58 +02001337 if (wl1271_set_block_size(wl))
1338 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001339 break;
1340 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001341 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001342 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001343 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001344 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001345 }
1346
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001347 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001348 ret = wl1271_fetch_firmware(wl);
1349 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001350 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001351 }
1352
1353 /* No NVS from netlink, try to get it from the filesystem */
1354 if (wl->nvs == NULL) {
1355 ret = wl1271_fetch_nvs(wl);
1356 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001357 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001358 }
1359
1360out:
1361 return ret;
1362}
1363
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364int wl1271_plt_start(struct wl1271 *wl)
1365{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001366 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001367 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368 int ret;
1369
1370 mutex_lock(&wl->mutex);
1371
1372 wl1271_notice("power up");
1373
1374 if (wl->state != WL1271_STATE_OFF) {
1375 wl1271_error("cannot go into PLT state because not "
1376 "in off state: %d", wl->state);
1377 ret = -EBUSY;
1378 goto out;
1379 }
1380
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001381 while (retries) {
1382 retries--;
1383 ret = wl1271_chip_wakeup(wl);
1384 if (ret < 0)
1385 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001386
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001387 ret = wl1271_boot(wl);
1388 if (ret < 0)
1389 goto power_off;
1390
1391 ret = wl1271_plt_init(wl);
1392 if (ret < 0)
1393 goto irq_disable;
1394
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001395 wl->state = WL1271_STATE_PLT;
1396 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001397 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001398
Gery Kahn6f07b722011-07-18 14:21:49 +03001399 /* update hw/fw version info in wiphy struct */
1400 wiphy->hw_version = wl->chip.id;
1401 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1402 sizeof(wiphy->fw_version));
1403
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001404 goto out;
1405
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001406irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001407 mutex_unlock(&wl->mutex);
1408 /* Unlocking the mutex in the middle of handling is
1409 inherently unsafe. In this case we deem it safe to do,
1410 because we need to let any possibly pending IRQ out of
1411 the system (and while we are WL1271_STATE_OFF the IRQ
1412 work function will not do anything.) Also, any other
1413 possible concurrent operations will fail due to the
1414 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001415 wl1271_disable_interrupts(wl);
1416 wl1271_flush_deferred_work(wl);
1417 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001418 mutex_lock(&wl->mutex);
1419power_off:
1420 wl1271_power_off(wl);
1421 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001422
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001423 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1424 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001425out:
1426 mutex_unlock(&wl->mutex);
1427
1428 return ret;
1429}
1430
Luciano Coelho4623ec72011-03-21 19:26:41 +02001431static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001432{
1433 int ret = 0;
1434
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001435 wl1271_notice("power down");
1436
1437 if (wl->state != WL1271_STATE_PLT) {
1438 wl1271_error("cannot power down because not in PLT "
1439 "state: %d", wl->state);
1440 ret = -EBUSY;
1441 goto out;
1442 }
1443
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444 wl1271_power_off(wl);
1445
1446 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001447 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001449 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001450 wl1271_disable_interrupts(wl);
1451 wl1271_flush_deferred_work(wl);
1452 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001453 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001454 mutex_lock(&wl->mutex);
1455out:
1456 return ret;
1457}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001458
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001459int wl1271_plt_stop(struct wl1271 *wl)
1460{
1461 int ret;
1462
1463 mutex_lock(&wl->mutex);
1464 ret = __wl1271_plt_stop(wl);
1465 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001466 return ret;
1467}
1468
Johannes Berg7bb45682011-02-24 14:42:06 +01001469static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001470{
1471 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001472 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1473 struct ieee80211_vif *vif = info->control.vif;
1474 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001475 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001476 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001477 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001478
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001479 mapping = skb_get_queue_mapping(skb);
1480 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001481
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001482 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001483
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001484 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001485
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001486 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001487 if (hlid == WL12XX_INVALID_LINK_ID ||
1488 !test_bit(hlid, wlvif->links_map)) {
1489 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
1490 dev_kfree_skb(skb);
1491 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001492 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001493
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001494 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1495 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1496
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001497 wl->tx_queue_count[q]++;
1498
1499 /*
1500 * The workqueue is slow to process the tx_queue and we need stop
1501 * the queue here, otherwise the queue will get too long.
1502 */
1503 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1504 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1505 ieee80211_stop_queue(wl->hw, mapping);
1506 set_bit(q, &wl->stopped_queues_map);
1507 }
1508
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001509 /*
1510 * The chip specific setup must run before the first TX packet -
1511 * before that, the tx_work will not be initialized!
1512 */
1513
Ido Yarivb07d4032011-03-01 15:14:43 +02001514 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1515 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001516 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001517
Arik Nemtsov04216da2011-08-14 13:17:38 +03001518out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001519 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001520}
1521
Shahar Leviae47c452011-03-06 16:32:14 +02001522int wl1271_tx_dummy_packet(struct wl1271 *wl)
1523{
Ido Yariv990f5de2011-03-31 10:06:59 +02001524 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001525 int q;
1526
1527 /* no need to queue a new dummy packet if one is already pending */
1528 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1529 return 0;
1530
1531 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001532
Ido Yariv990f5de2011-03-31 10:06:59 +02001533 spin_lock_irqsave(&wl->wl_lock, flags);
1534 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001535 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001536 spin_unlock_irqrestore(&wl->wl_lock, flags);
1537
1538 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1539 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Peller536129c2011-10-05 11:55:45 +02001540 wl1271_tx_work_locked(wl, wl->vif);
Ido Yariv990f5de2011-03-31 10:06:59 +02001541
1542 /*
1543 * If the FW TX is busy, TX work will be scheduled by the threaded
1544 * interrupt handler function
1545 */
1546 return 0;
1547}
1548
1549/*
1550 * The size of the dummy packet should be at least 1400 bytes. However, in
1551 * order to minimize the number of bus transactions, aligning it to 512 bytes
1552 * boundaries could be beneficial, performance wise
1553 */
1554#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1555
Luciano Coelhocf27d862011-04-01 21:08:23 +03001556static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001557{
1558 struct sk_buff *skb;
1559 struct ieee80211_hdr_3addr *hdr;
1560 unsigned int dummy_packet_size;
1561
1562 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1563 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1564
1565 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001566 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001567 wl1271_warning("Failed to allocate a dummy packet skb");
1568 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001569 }
1570
1571 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1572
1573 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1574 memset(hdr, 0, sizeof(*hdr));
1575 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001576 IEEE80211_STYPE_NULLFUNC |
1577 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001578
Ido Yariv990f5de2011-03-31 10:06:59 +02001579 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001580
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001581 /* Dummy packets require the TID to be management */
1582 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001583
1584 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001585 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001586 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001587
Ido Yariv990f5de2011-03-31 10:06:59 +02001588 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001589}
1590
Ido Yariv990f5de2011-03-31 10:06:59 +02001591
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001592static struct notifier_block wl1271_dev_notifier = {
1593 .notifier_call = wl1271_dev_notify,
1594};
1595
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001596#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001597static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1598 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001599{
Eliad Pellere85d1622011-06-27 13:06:43 +03001600 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001601
Eliad Peller94390642011-05-13 11:57:13 +03001602 mutex_lock(&wl->mutex);
1603
Eliad Pellere85d1622011-06-27 13:06:43 +03001604 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1605 goto out_unlock;
1606
Eliad Peller94390642011-05-13 11:57:13 +03001607 ret = wl1271_ps_elp_wakeup(wl);
1608 if (ret < 0)
1609 goto out_unlock;
1610
1611 /* enter psm if needed*/
1612 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1613 DECLARE_COMPLETION_ONSTACK(compl);
1614
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001615 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001616 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001617 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001618 if (ret < 0)
1619 goto out_sleep;
1620
1621 /* we must unlock here so we will be able to get events */
1622 wl1271_ps_elp_sleep(wl);
1623 mutex_unlock(&wl->mutex);
1624
1625 ret = wait_for_completion_timeout(
1626 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1627 if (ret <= 0) {
1628 wl1271_warning("couldn't enter ps mode!");
1629 ret = -EBUSY;
1630 goto out;
1631 }
1632
1633 /* take mutex again, and wakeup */
1634 mutex_lock(&wl->mutex);
1635
1636 ret = wl1271_ps_elp_wakeup(wl);
1637 if (ret < 0)
1638 goto out_unlock;
1639 }
1640out_sleep:
1641 wl1271_ps_elp_sleep(wl);
1642out_unlock:
1643 mutex_unlock(&wl->mutex);
1644out:
1645 return ret;
1646
1647}
1648
Eliad Peller0603d892011-10-05 11:55:51 +02001649static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1650 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001651{
Eliad Pellere85d1622011-06-27 13:06:43 +03001652 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001653
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001654 mutex_lock(&wl->mutex);
1655
Eliad Pellere85d1622011-06-27 13:06:43 +03001656 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1657 goto out_unlock;
1658
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001659 ret = wl1271_ps_elp_wakeup(wl);
1660 if (ret < 0)
1661 goto out_unlock;
1662
Eliad Peller0603d892011-10-05 11:55:51 +02001663 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001664
1665 wl1271_ps_elp_sleep(wl);
1666out_unlock:
1667 mutex_unlock(&wl->mutex);
1668 return ret;
1669
1670}
1671
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001672static int wl1271_configure_suspend(struct wl1271 *wl,
1673 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001674{
Eliad Peller536129c2011-10-05 11:55:45 +02001675 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001676 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001677 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001678 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001679 return 0;
1680}
1681
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001682static void wl1271_configure_resume(struct wl1271 *wl,
1683 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001684{
1685 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02001686 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1687 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001688
1689 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001690 return;
1691
1692 mutex_lock(&wl->mutex);
1693 ret = wl1271_ps_elp_wakeup(wl);
1694 if (ret < 0)
1695 goto out;
1696
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001697 if (is_sta) {
1698 /* exit psm if it wasn't configured */
1699 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001700 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001701 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001702 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001703 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001704 }
Eliad Peller94390642011-05-13 11:57:13 +03001705
1706 wl1271_ps_elp_sleep(wl);
1707out:
1708 mutex_unlock(&wl->mutex);
1709}
1710
Eliad Peller402e48612011-05-13 11:57:09 +03001711static int wl1271_op_suspend(struct ieee80211_hw *hw,
1712 struct cfg80211_wowlan *wow)
1713{
1714 struct wl1271 *wl = hw->priv;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001715 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
1716 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001717 int ret;
1718
Eliad Peller402e48612011-05-13 11:57:09 +03001719 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001720 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001721
Eliad Peller4a859df2011-06-06 12:21:52 +03001722 wl->wow_enabled = true;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001723 ret = wl1271_configure_suspend(wl, wlvif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001724 if (ret < 0) {
1725 wl1271_warning("couldn't prepare device to suspend");
1726 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001727 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001728 /* flush any remaining work */
1729 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001730
1731 /*
1732 * disable and re-enable interrupts in order to flush
1733 * the threaded_irq
1734 */
1735 wl1271_disable_interrupts(wl);
1736
1737 /*
1738 * set suspended flag to avoid triggering a new threaded_irq
1739 * work. no need for spinlock as interrupts are disabled.
1740 */
1741 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1742
1743 wl1271_enable_interrupts(wl);
1744 flush_work(&wl->tx_work);
Eliad Peller252efa42011-10-05 11:56:00 +02001745 flush_delayed_work(&wlvif->pspoll_work);
Eliad Peller4a859df2011-06-06 12:21:52 +03001746 flush_delayed_work(&wl->elp_work);
1747
Eliad Peller402e48612011-05-13 11:57:09 +03001748 return 0;
1749}
1750
1751static int wl1271_op_resume(struct ieee80211_hw *hw)
1752{
1753 struct wl1271 *wl = hw->priv;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001754 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
1755 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4a859df2011-06-06 12:21:52 +03001756 unsigned long flags;
1757 bool run_irq_work = false;
1758
Eliad Peller402e48612011-05-13 11:57:09 +03001759 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1760 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001761 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001762
1763 /*
1764 * re-enable irq_work enqueuing, and call irq_work directly if
1765 * there is a pending work.
1766 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001767 spin_lock_irqsave(&wl->wl_lock, flags);
1768 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1769 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1770 run_irq_work = true;
1771 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001772
Eliad Peller4a859df2011-06-06 12:21:52 +03001773 if (run_irq_work) {
1774 wl1271_debug(DEBUG_MAC80211,
1775 "run postponed irq_work directly");
1776 wl1271_irq(0, wl);
1777 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001778 }
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001779 wl1271_configure_resume(wl, wlvif);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001780 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001781
Eliad Peller402e48612011-05-13 11:57:09 +03001782 return 0;
1783}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001784#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001785
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001786static int wl1271_op_start(struct ieee80211_hw *hw)
1787{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001788 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1789
1790 /*
1791 * We have to delay the booting of the hardware because
1792 * we need to know the local MAC address before downloading and
1793 * initializing the firmware. The MAC address cannot be changed
1794 * after boot, and without the proper MAC address, the firmware
1795 * will not function properly.
1796 *
1797 * The MAC address is first known when the corresponding interface
1798 * is added. That is where we will initialize the hardware.
1799 */
1800
1801 return 0;
1802}
1803
1804static void wl1271_op_stop(struct ieee80211_hw *hw)
1805{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001806 struct wl1271 *wl = hw->priv;
1807 int i;
1808
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001809 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001810
1811 mutex_lock(&wl_list_mutex);
1812 list_del(&wl->list);
1813
1814 /*
1815 * this must be before the cancel_work calls below, so that the work
1816 * functions don't perform further work.
1817 */
1818 wl->state = WL1271_STATE_OFF;
1819 mutex_unlock(&wl_list_mutex);
1820
1821 wl1271_disable_interrupts(wl);
1822 wl1271_flush_deferred_work(wl);
1823 cancel_delayed_work_sync(&wl->scan_complete_work);
1824 cancel_work_sync(&wl->netstack_work);
1825 cancel_work_sync(&wl->tx_work);
1826 del_timer_sync(&wl->rx_streaming_timer);
1827 cancel_work_sync(&wl->rx_streaming_enable_work);
1828 cancel_work_sync(&wl->rx_streaming_disable_work);
1829 cancel_delayed_work_sync(&wl->elp_work);
1830
1831 /* let's notify MAC80211 about the remaining pending TX frames */
1832 wl12xx_tx_reset(wl, true);
1833 mutex_lock(&wl->mutex);
1834
1835 wl1271_power_off(wl);
1836
1837 wl->band = IEEE80211_BAND_2GHZ;
1838
1839 wl->rx_counter = 0;
1840 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1841 wl->tx_blocks_available = 0;
1842 wl->tx_allocated_blocks = 0;
1843 wl->tx_results_count = 0;
1844 wl->tx_packets_count = 0;
1845 wl->time_offset = 0;
1846 wl->vif = NULL;
1847 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1848 wl->ap_fw_ps_map = 0;
1849 wl->ap_ps_map = 0;
1850 wl->sched_scanning = false;
1851 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1852 memset(wl->links_map, 0, sizeof(wl->links_map));
1853 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1854 wl->active_sta_count = 0;
1855
1856 /* The system link is always allocated */
1857 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1858
1859 /*
1860 * this is performed after the cancel_work calls and the associated
1861 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1862 * get executed before all these vars have been reset.
1863 */
1864 wl->flags = 0;
1865
1866 wl->tx_blocks_freed = 0;
1867
1868 for (i = 0; i < NUM_TX_QUEUES; i++) {
1869 wl->tx_pkts_freed[i] = 0;
1870 wl->tx_allocated_pkts[i] = 0;
1871 }
1872
1873 wl1271_debugfs_reset(wl);
1874
1875 kfree(wl->fw_status);
1876 wl->fw_status = NULL;
1877 kfree(wl->tx_res_if);
1878 wl->tx_res_if = NULL;
1879 kfree(wl->target_mem_map);
1880 wl->target_mem_map = NULL;
1881
1882 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001883}
1884
Eliad Peller536129c2011-10-05 11:55:45 +02001885static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001886{
Eliad Peller536129c2011-10-05 11:55:45 +02001887 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001888 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001889 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001890 return WL1271_ROLE_P2P_GO;
1891 else
1892 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001893
1894 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001895 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001896 return WL1271_ROLE_P2P_CL;
1897 else
1898 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001899
Eliad Peller227e81e2011-08-14 13:17:26 +03001900 case BSS_TYPE_IBSS:
1901 return WL1271_ROLE_IBSS;
1902
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001903 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001904 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001905 }
1906 return WL12XX_INVALID_ROLE_TYPE;
1907}
1908
Eliad Peller83587502011-10-10 10:12:53 +02001909static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001910{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001911 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
1912
1913 /* make sure wlvif is zeroed */
1914 memset(wlvif, 0, sizeof(*wlvif));
1915
1916 switch (ieee80211_vif_type_p2p(vif)) {
1917 case NL80211_IFTYPE_P2P_CLIENT:
1918 wlvif->p2p = 1;
1919 /* fall-through */
1920 case NL80211_IFTYPE_STATION:
1921 wlvif->bss_type = BSS_TYPE_STA_BSS;
1922 break;
1923 case NL80211_IFTYPE_ADHOC:
1924 wlvif->bss_type = BSS_TYPE_IBSS;
1925 break;
1926 case NL80211_IFTYPE_P2P_GO:
1927 wlvif->p2p = 1;
1928 /* fall-through */
1929 case NL80211_IFTYPE_AP:
1930 wlvif->bss_type = BSS_TYPE_AP_BSS;
1931 break;
1932 default:
1933 wlvif->bss_type = MAX_BSS_TYPE;
1934 return -EOPNOTSUPP;
1935 }
1936
Eliad Peller0603d892011-10-05 11:55:51 +02001937 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001938 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001939 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001940
Eliad Pellere936bbe2011-10-05 11:55:56 +02001941 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1942 wlvif->bss_type == BSS_TYPE_IBSS) {
1943 /* init sta/ibss data */
1944 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
1945
1946 } else {
1947 /* init ap data */
1948 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1949 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
1950 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001951
Eliad Peller83587502011-10-10 10:12:53 +02001952 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1953 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001954 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001955 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001956 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001957 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1958
Eliad Peller252efa42011-10-05 11:56:00 +02001959 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller87627212011-10-10 10:12:54 +02001960 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001961
Eliad Pellere936bbe2011-10-05 11:55:56 +02001962 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001963}
1964
Eliad Peller1d095472011-10-10 10:12:49 +02001965static bool wl12xx_init_fw(struct wl1271 *wl)
1966{
1967 int retries = WL1271_BOOT_RETRIES;
1968 bool booted = false;
1969 struct wiphy *wiphy = wl->hw->wiphy;
1970 int ret;
1971
1972 while (retries) {
1973 retries--;
1974 ret = wl1271_chip_wakeup(wl);
1975 if (ret < 0)
1976 goto power_off;
1977
1978 ret = wl1271_boot(wl);
1979 if (ret < 0)
1980 goto power_off;
1981
1982 ret = wl1271_hw_init(wl);
1983 if (ret < 0)
1984 goto irq_disable;
1985
1986 booted = true;
1987 break;
1988
1989irq_disable:
1990 mutex_unlock(&wl->mutex);
1991 /* Unlocking the mutex in the middle of handling is
1992 inherently unsafe. In this case we deem it safe to do,
1993 because we need to let any possibly pending IRQ out of
1994 the system (and while we are WL1271_STATE_OFF the IRQ
1995 work function will not do anything.) Also, any other
1996 possible concurrent operations will fail due to the
1997 current state, hence the wl1271 struct should be safe. */
1998 wl1271_disable_interrupts(wl);
1999 wl1271_flush_deferred_work(wl);
2000 cancel_work_sync(&wl->netstack_work);
2001 mutex_lock(&wl->mutex);
2002power_off:
2003 wl1271_power_off(wl);
2004 }
2005
2006 if (!booted) {
2007 wl1271_error("firmware boot failed despite %d retries",
2008 WL1271_BOOT_RETRIES);
2009 goto out;
2010 }
2011
2012 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2013
2014 /* update hw/fw version info in wiphy struct */
2015 wiphy->hw_version = wl->chip.id;
2016 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2017 sizeof(wiphy->fw_version));
2018
2019 /*
2020 * Now we know if 11a is supported (info from the NVS), so disable
2021 * 11a channels if not supported
2022 */
2023 if (!wl->enable_11a)
2024 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2025
2026 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2027 wl->enable_11a ? "" : "not ");
2028
2029 wl->state = WL1271_STATE_ON;
2030out:
2031 return booted;
2032}
2033
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002034static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2035 struct ieee80211_vif *vif)
2036{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002037 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002038 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002039 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002040 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002041 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002042
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002043 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002044 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002045
2046 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002047 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002048 wl1271_debug(DEBUG_MAC80211,
2049 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002050 ret = -EBUSY;
2051 goto out;
2052 }
2053
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002054 /*
2055 * in some very corner case HW recovery scenarios its possible to
2056 * get here before __wl1271_op_remove_interface is complete, so
2057 * opt out if that is the case.
2058 */
2059 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
2060 ret = -EBUSY;
2061 goto out;
2062 }
2063
Eliad Peller83587502011-10-10 10:12:53 +02002064 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002065 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002066 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002067
Eliad Peller252efa42011-10-05 11:56:00 +02002068 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002069 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002070 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2071 ret = -EINVAL;
2072 goto out;
2073 }
Eliad Peller1d095472011-10-10 10:12:49 +02002074
Eliad Peller784f6942011-10-05 11:55:39 +02002075 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002076 * TODO: after the nvs issue will be solved, move this block
2077 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002078 */
Eliad Peller1d095472011-10-10 10:12:49 +02002079 if (wl->state == WL1271_STATE_OFF) {
2080 /*
2081 * we still need this in order to configure the fw
2082 * while uploading the nvs
2083 */
2084 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002085
Eliad Peller1d095472011-10-10 10:12:49 +02002086 booted = wl12xx_init_fw(wl);
2087 if (!booted) {
2088 ret = -EINVAL;
2089 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002090 }
Eliad Peller1d095472011-10-10 10:12:49 +02002091 }
Eliad Peller04e80792011-08-14 13:17:09 +03002092
Eliad Peller1d095472011-10-10 10:12:49 +02002093 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2094 wlvif->bss_type == BSS_TYPE_IBSS) {
2095 /*
2096 * The device role is a special role used for
2097 * rx and tx frames prior to association (as
2098 * the STA role can get packets only from
2099 * its associated bssid)
2100 */
Eliad Peller784f6942011-10-05 11:55:39 +02002101 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002102 WL1271_ROLE_DEVICE,
2103 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002104 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002105 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002106 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002107
Eliad Peller1d095472011-10-10 10:12:49 +02002108 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2109 role_type, &wlvif->role_id);
2110 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002111 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002112
2113 ret = wl1271_init_vif_specific(wl, vif);
2114 if (ret < 0)
2115 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002116
2117 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002118 list_add(&wlvif->list, &wl->wlvif_list);
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002119 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002120out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002121 mutex_unlock(&wl->mutex);
2122
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002123 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002124 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002125 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002126 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002127
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002128 return ret;
2129}
2130
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002131static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002132 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002133 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002134{
Eliad Peller536129c2011-10-05 11:55:45 +02002135 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002136 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002137
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002138 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002139
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002140 /* because of hardware recovery, we may get here twice */
2141 if (wl->state != WL1271_STATE_ON)
2142 return;
2143
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002144 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002145
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002146 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c2011-10-05 11:55:45 +02002147 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002148 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002149
Eliad Pellerbaf62772011-10-10 10:12:52 +02002150 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2151 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002152 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002153 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002154 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002155 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002156 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002157 }
2158
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002159 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2160 /* disable active roles */
2161 ret = wl1271_ps_elp_wakeup(wl);
2162 if (ret < 0)
2163 goto deinit;
2164
Eliad Peller536129c2011-10-05 11:55:45 +02002165 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002166 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002167 if (ret < 0)
2168 goto deinit;
2169 }
2170
Eliad Peller0603d892011-10-05 11:55:51 +02002171 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002172 if (ret < 0)
2173 goto deinit;
2174
2175 wl1271_ps_elp_sleep(wl);
2176 }
2177deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002178 /* clear all hlids (except system_hlid) */
Eliad Peller154da672011-10-05 11:55:53 +02002179 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002180 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002181 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2182 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002183
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002184 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002185 wl1271_free_ap_keys(wl, wlvif);
Eliad Peller87627212011-10-10 10:12:54 +02002186 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002187 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002188 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002189 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002190
Eliad Pellerbaf62772011-10-10 10:12:52 +02002191 mutex_unlock(&wl->mutex);
2192 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002193
Eliad Pellerbaf62772011-10-10 10:12:52 +02002194 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002195}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002196
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002197static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2198 struct ieee80211_vif *vif)
2199{
2200 struct wl1271 *wl = hw->priv;
2201
2202 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002203 /*
2204 * wl->vif can be null here if someone shuts down the interface
2205 * just when hardware recovery has been started.
2206 */
2207 if (wl->vif) {
2208 WARN_ON(wl->vif != vif);
Eliad Peller536129c2011-10-05 11:55:45 +02002209 __wl1271_op_remove_interface(wl, vif, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002210 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002211
Juuso Oikarinen67353292010-11-18 15:19:02 +02002212 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002213 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002214}
2215
Eliad Peller87fbcb02011-10-05 11:55:41 +02002216static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2217 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002218{
2219 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002220 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002221
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002222 /*
2223 * One of the side effects of the JOIN command is that is clears
2224 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2225 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002226 * Currently the only valid scenario for JOIN during association
2227 * is on roaming, in which case we will also be given new keys.
2228 * Keep the below message for now, unless it starts bothering
2229 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002230 */
2231 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2232 wl1271_info("JOIN while associated.");
2233
2234 if (set_assoc)
2235 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2236
Eliad Peller227e81e2011-08-14 13:17:26 +03002237 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002238 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002239 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002240 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002241 if (ret < 0)
2242 goto out;
2243
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002244 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2245 goto out;
2246
2247 /*
2248 * The join command disable the keep-alive mode, shut down its process,
2249 * and also clear the template config, so we need to reset it all after
2250 * the join. The acx_aid starts the keep-alive process, and the order
2251 * of the commands below is relevant.
2252 */
Eliad Peller0603d892011-10-05 11:55:51 +02002253 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002254 if (ret < 0)
2255 goto out;
2256
Eliad Peller0603d892011-10-05 11:55:51 +02002257 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002258 if (ret < 0)
2259 goto out;
2260
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002261 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002262 if (ret < 0)
2263 goto out;
2264
Eliad Peller0603d892011-10-05 11:55:51 +02002265 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2266 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002267 ACX_KEEP_ALIVE_TPL_VALID);
2268 if (ret < 0)
2269 goto out;
2270
2271out:
2272 return ret;
2273}
2274
Eliad Peller0603d892011-10-05 11:55:51 +02002275static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002276{
2277 int ret;
2278
Shahar Levi6d158ff2011-09-08 13:01:33 +03002279 if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags)) {
2280 wl12xx_cmd_stop_channel_switch(wl);
2281 ieee80211_chswitch_done(wl->vif, false);
2282 }
2283
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002284 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002285 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002286 if (ret < 0)
2287 goto out;
2288
Oz Krakowskib992c682011-06-26 10:36:02 +03002289 /* reset TX security counters on a clean disconnect */
2290 wl->tx_security_last_seq_lsb = 0;
2291 wl->tx_security_seq = 0;
2292
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002293out:
2294 return ret;
2295}
2296
Eliad Peller87fbcb02011-10-05 11:55:41 +02002297static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002298{
Eliad Peller83587502011-10-10 10:12:53 +02002299 wlvif->basic_rate_set = wlvif->bitrate_masks[wl->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002300 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002301}
2302
Eliad Peller251c1772011-08-14 13:17:17 +03002303static bool wl12xx_is_roc(struct wl1271 *wl)
2304{
2305 u8 role_id;
2306
2307 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2308 if (role_id >= WL12XX_MAX_ROLES)
2309 return false;
2310
2311 return true;
2312}
2313
Eliad Peller87fbcb02011-10-05 11:55:41 +02002314static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2315 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002316{
2317 int ret;
2318
2319 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002320 /* no need to croc if we weren't busy (e.g. during boot) */
2321 if (wl12xx_is_roc(wl)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002322 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002323 if (ret < 0)
2324 goto out;
2325
Eliad Peller7edebf52011-10-05 11:55:52 +02002326 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002327 if (ret < 0)
2328 goto out;
2329 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002330 wlvif->rate_set =
2331 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2332 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002333 if (ret < 0)
2334 goto out;
2335 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002336 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002337 ACX_KEEP_ALIVE_TPL_INVALID);
2338 if (ret < 0)
2339 goto out;
2340 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2341 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002342 /* The current firmware only supports sched_scan in idle */
2343 if (wl->sched_scanning) {
2344 wl1271_scan_sched_scan_stop(wl);
2345 ieee80211_sched_scan_stopped(wl->hw);
2346 }
2347
Eliad Peller7edebf52011-10-05 11:55:52 +02002348 ret = wl12xx_cmd_role_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002349 if (ret < 0)
2350 goto out;
2351
Eliad Peller7edebf52011-10-05 11:55:52 +02002352 ret = wl12xx_roc(wl, wlvif->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002353 if (ret < 0)
2354 goto out;
2355 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2356 }
2357
2358out:
2359 return ret;
2360}
2361
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002362static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2363{
2364 struct wl1271 *wl = hw->priv;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002365 struct ieee80211_vif *vif = wl->vif; /* TODO: reconfig all vifs */
2366 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002367 struct ieee80211_conf *conf = &hw->conf;
2368 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002369 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002370
2371 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2372
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002373 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2374 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002375 channel,
2376 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002377 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002378 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2379 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002380
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002381 /*
2382 * mac80211 will go to idle nearly immediately after transmitting some
2383 * frames, such as the deauth. To make sure those frames reach the air,
2384 * wait here until the TX queue is fully flushed.
2385 */
2386 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2387 (conf->flags & IEEE80211_CONF_IDLE))
2388 wl1271_tx_flush(wl);
2389
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002390 mutex_lock(&wl->mutex);
2391
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002392 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002393 /* we support configuring the channel and band while off */
2394 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2395 wl->band = conf->channel->band;
2396 wl->channel = channel;
2397 }
2398
Arik Nemtsov097f8822011-06-27 22:06:34 +03002399 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2400 wl->power_level = conf->power_level;
2401
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002402 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002403 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002404
Eliad Peller536129c2011-10-05 11:55:45 +02002405 is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002406
Ido Yariva6208652011-03-01 15:14:41 +02002407 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002408 if (ret < 0)
2409 goto out;
2410
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002411 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002412 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2413 ((wl->band != conf->channel->band) ||
2414 (wl->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002415 /* send all pending packets */
Eliad Peller536129c2011-10-05 11:55:45 +02002416 wl1271_tx_work_locked(wl, vif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002417 wl->band = conf->channel->band;
2418 wl->channel = channel;
2419
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002420 if (!is_ap) {
2421 /*
2422 * FIXME: the mac80211 should really provide a fixed
2423 * rate to use here. for now, just use the smallest
2424 * possible rate for the band as a fixed rate for
2425 * association frames and other control messages.
2426 */
2427 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002428 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002429
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002430 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002431 wl1271_tx_min_rate_get(wl,
2432 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002433 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002434 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002435 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002436 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002437
Eliad Peller251c1772011-08-14 13:17:17 +03002438 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2439 if (wl12xx_is_roc(wl)) {
2440 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002441 ret = wl12xx_croc(wl,
2442 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002443 if (ret < 0)
2444 goto out_sleep;
2445 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002446 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002447 if (ret < 0)
2448 wl1271_warning("cmd join on channel "
2449 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002450 } else {
2451 /*
2452 * change the ROC channel. do it only if we are
2453 * not idle. otherwise, CROC will be called
2454 * anyway.
2455 */
2456 if (wl12xx_is_roc(wl) &&
2457 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02002458 ret = wl12xx_croc(wl,
2459 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002460 if (ret < 0)
2461 goto out_sleep;
2462
Eliad Peller7edebf52011-10-05 11:55:52 +02002463 ret = wl12xx_roc(wl,
2464 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002465 if (ret < 0)
2466 wl1271_warning("roc failed %d",
2467 ret);
2468 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002469 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002470 }
2471 }
2472
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002473 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02002474 ret = wl1271_sta_handle_idle(wl, wlvif,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002475 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002476 if (ret < 0)
2477 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002478 }
2479
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002480 /*
2481 * if mac80211 changes the PSM mode, make sure the mode is not
2482 * incorrectly changed after the pspoll failure active window.
2483 */
2484 if (changed & IEEE80211_CONF_CHANGE_PS)
2485 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2486
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002487 if (conf->flags & IEEE80211_CONF_PS &&
2488 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2489 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002490
2491 /*
2492 * We enter PSM only if we're already associated.
2493 * If we're not, we'll enter it when joining an SSID,
2494 * through the bss_info_changed() hook.
2495 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002496 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002497 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002498 ret = wl1271_ps_set_mode(wl, wlvif,
2499 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002500 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002501 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002502 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002503 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002504 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002505
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002506 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002507
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002508 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002509 ret = wl1271_ps_set_mode(wl, wlvif,
2510 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002511 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002512 }
2513
2514 if (conf->power_level != wl->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002515 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002516 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002517 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002518
2519 wl->power_level = conf->power_level;
2520 }
2521
2522out_sleep:
2523 wl1271_ps_elp_sleep(wl);
2524
2525out:
2526 mutex_unlock(&wl->mutex);
2527
2528 return ret;
2529}
2530
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002531struct wl1271_filter_params {
2532 bool enabled;
2533 int mc_list_length;
2534 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2535};
2536
Jiri Pirko22bedad2010-04-01 21:22:57 +00002537static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2538 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002539{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002540 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002541 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002542 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002543
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002544 if (unlikely(wl->state == WL1271_STATE_OFF))
2545 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002546
Juuso Oikarinen74441132009-10-13 12:47:53 +03002547 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002548 if (!fp) {
2549 wl1271_error("Out of memory setting filters.");
2550 return 0;
2551 }
2552
2553 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002554 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002555 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2556 fp->enabled = false;
2557 } else {
2558 fp->enabled = true;
2559 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002560 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002561 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002562 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002563 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002564 }
2565
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002566 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002567}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002568
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002569#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2570 FIF_ALLMULTI | \
2571 FIF_FCSFAIL | \
2572 FIF_BCN_PRBRESP_PROMISC | \
2573 FIF_CONTROL | \
2574 FIF_OTHER_BSS)
2575
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002576static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2577 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002578 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002579{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002580 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002581 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002582 struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
2583 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2584
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002585 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002586
Arik Nemtsov7d057862010-10-16 19:25:35 +02002587 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2588 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002589
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002590 mutex_lock(&wl->mutex);
2591
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002592 *total &= WL1271_SUPPORTED_FILTERS;
2593 changed &= WL1271_SUPPORTED_FILTERS;
2594
2595 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002596 goto out;
2597
Ido Yariva6208652011-03-01 15:14:41 +02002598 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002599 if (ret < 0)
2600 goto out;
2601
Eliad Peller536129c2011-10-05 11:55:45 +02002602 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
Arik Nemtsov7d057862010-10-16 19:25:35 +02002603 if (*total & FIF_ALLMULTI)
Eliad Peller0603d892011-10-05 11:55:51 +02002604 ret = wl1271_acx_group_address_tbl(wl, wlvif, false,
2605 NULL, 0);
Arik Nemtsov7d057862010-10-16 19:25:35 +02002606 else if (fp)
Eliad Peller0603d892011-10-05 11:55:51 +02002607 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2608 fp->enabled,
Arik Nemtsov7d057862010-10-16 19:25:35 +02002609 fp->mc_list,
2610 fp->mc_list_length);
2611 if (ret < 0)
2612 goto out_sleep;
2613 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002614
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002615 /*
2616 * the fw doesn't provide an api to configure the filters. instead,
2617 * the filters configuration is based on the active roles / ROC
2618 * state.
2619 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002620
2621out_sleep:
2622 wl1271_ps_elp_sleep(wl);
2623
2624out:
2625 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002626 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002627}
2628
Eliad Peller170d0e62011-10-05 11:56:06 +02002629static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2630 u8 id, u8 key_type, u8 key_size,
2631 const u8 *key, u8 hlid, u32 tx_seq_32,
2632 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002633{
2634 struct wl1271_ap_key *ap_key;
2635 int i;
2636
2637 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2638
2639 if (key_size > MAX_KEY_SIZE)
2640 return -EINVAL;
2641
2642 /*
2643 * Find next free entry in ap_keys. Also check we are not replacing
2644 * an existing key.
2645 */
2646 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002647 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002648 break;
2649
Eliad Peller170d0e62011-10-05 11:56:06 +02002650 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002651 wl1271_warning("trying to record key replacement");
2652 return -EINVAL;
2653 }
2654 }
2655
2656 if (i == MAX_NUM_KEYS)
2657 return -EBUSY;
2658
2659 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2660 if (!ap_key)
2661 return -ENOMEM;
2662
2663 ap_key->id = id;
2664 ap_key->key_type = key_type;
2665 ap_key->key_size = key_size;
2666 memcpy(ap_key->key, key, key_size);
2667 ap_key->hlid = hlid;
2668 ap_key->tx_seq_32 = tx_seq_32;
2669 ap_key->tx_seq_16 = tx_seq_16;
2670
Eliad Peller170d0e62011-10-05 11:56:06 +02002671 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002672 return 0;
2673}
2674
Eliad Peller170d0e62011-10-05 11:56:06 +02002675static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002676{
2677 int i;
2678
2679 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002680 kfree(wlvif->ap.recorded_keys[i]);
2681 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002682 }
2683}
2684
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002685static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002686{
2687 int i, ret = 0;
2688 struct wl1271_ap_key *key;
2689 bool wep_key_added = false;
2690
2691 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002692 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002693 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002694 break;
2695
Eliad Peller170d0e62011-10-05 11:56:06 +02002696 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002697 hlid = key->hlid;
2698 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002699 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002700
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002701 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002702 key->id, key->key_type,
2703 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002704 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002705 key->tx_seq_16);
2706 if (ret < 0)
2707 goto out;
2708
2709 if (key->key_type == KEY_WEP)
2710 wep_key_added = true;
2711 }
2712
2713 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002714 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002715 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002716 if (ret < 0)
2717 goto out;
2718 }
2719
2720out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002721 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002722 return ret;
2723}
2724
Eliad Peller536129c2011-10-05 11:55:45 +02002725static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2726 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002727 u8 key_size, const u8 *key, u32 tx_seq_32,
2728 u16 tx_seq_16, struct ieee80211_sta *sta)
2729{
2730 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002731 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002732
2733 if (is_ap) {
2734 struct wl1271_station *wl_sta;
2735 u8 hlid;
2736
2737 if (sta) {
2738 wl_sta = (struct wl1271_station *)sta->drv_priv;
2739 hlid = wl_sta->hlid;
2740 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002741 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002742 }
2743
2744 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2745 /*
2746 * We do not support removing keys after AP shutdown.
2747 * Pretend we do to make mac80211 happy.
2748 */
2749 if (action != KEY_ADD_OR_REPLACE)
2750 return 0;
2751
Eliad Peller170d0e62011-10-05 11:56:06 +02002752 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002753 key_type, key_size,
2754 key, hlid, tx_seq_32,
2755 tx_seq_16);
2756 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002757 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002758 id, key_type, key_size,
2759 key, hlid, tx_seq_32,
2760 tx_seq_16);
2761 }
2762
2763 if (ret < 0)
2764 return ret;
2765 } else {
2766 const u8 *addr;
2767 static const u8 bcast_addr[ETH_ALEN] = {
2768 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2769 };
2770
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002771 /*
2772 * A STA set to GEM cipher requires 2 tx spare blocks.
2773 * Return to default value when GEM cipher key is removed
2774 */
2775 if (key_type == KEY_GEM) {
2776 if (action == KEY_ADD_OR_REPLACE)
2777 wl->tx_spare_blocks = 2;
2778 else if (action == KEY_REMOVE)
2779 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2780 }
2781
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002782 addr = sta ? sta->addr : bcast_addr;
2783
2784 if (is_zero_ether_addr(addr)) {
2785 /* We dont support TX only encryption */
2786 return -EOPNOTSUPP;
2787 }
2788
2789 /* The wl1271 does not allow to remove unicast keys - they
2790 will be cleared automatically on next CMD_JOIN. Ignore the
2791 request silently, as we dont want the mac80211 to emit
2792 an error message. */
2793 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2794 return 0;
2795
Eliad Peller010d3d32011-08-14 13:17:31 +03002796 /* don't remove key if hlid was already deleted */
2797 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002798 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002799 return 0;
2800
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002801 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002802 id, key_type, key_size,
2803 key, addr, tx_seq_32,
2804 tx_seq_16);
2805 if (ret < 0)
2806 return ret;
2807
2808 /* the default WEP key needs to be configured at least once */
2809 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002810 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002811 wlvif->default_key,
2812 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002813 if (ret < 0)
2814 return ret;
2815 }
2816 }
2817
2818 return 0;
2819}
2820
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002821static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2822 struct ieee80211_vif *vif,
2823 struct ieee80211_sta *sta,
2824 struct ieee80211_key_conf *key_conf)
2825{
2826 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002827 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002828 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002829 u32 tx_seq_32 = 0;
2830 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002831 u8 key_type;
2832
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002833 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2834
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002835 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002836 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002837 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002838 key_conf->keylen, key_conf->flags);
2839 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2840
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002841 mutex_lock(&wl->mutex);
2842
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002843 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2844 ret = -EAGAIN;
2845 goto out_unlock;
2846 }
2847
Ido Yariva6208652011-03-01 15:14:41 +02002848 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002849 if (ret < 0)
2850 goto out_unlock;
2851
Johannes Berg97359d12010-08-10 09:46:38 +02002852 switch (key_conf->cipher) {
2853 case WLAN_CIPHER_SUITE_WEP40:
2854 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002855 key_type = KEY_WEP;
2856
2857 key_conf->hw_key_idx = key_conf->keyidx;
2858 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002859 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002860 key_type = KEY_TKIP;
2861
2862 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002863 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2864 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002865 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002866 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002867 key_type = KEY_AES;
2868
2869 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002870 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2871 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002872 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002873 case WL1271_CIPHER_SUITE_GEM:
2874 key_type = KEY_GEM;
2875 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2876 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2877 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002878 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002879 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002880
2881 ret = -EOPNOTSUPP;
2882 goto out_sleep;
2883 }
2884
2885 switch (cmd) {
2886 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002887 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002888 key_conf->keyidx, key_type,
2889 key_conf->keylen, key_conf->key,
2890 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002891 if (ret < 0) {
2892 wl1271_error("Could not add or replace key");
2893 goto out_sleep;
2894 }
2895 break;
2896
2897 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002898 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002899 key_conf->keyidx, key_type,
2900 key_conf->keylen, key_conf->key,
2901 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002902 if (ret < 0) {
2903 wl1271_error("Could not remove key");
2904 goto out_sleep;
2905 }
2906 break;
2907
2908 default:
2909 wl1271_error("Unsupported key cmd 0x%x", cmd);
2910 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002911 break;
2912 }
2913
2914out_sleep:
2915 wl1271_ps_elp_sleep(wl);
2916
2917out_unlock:
2918 mutex_unlock(&wl->mutex);
2919
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002920 return ret;
2921}
2922
2923static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002924 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002925 struct cfg80211_scan_request *req)
2926{
2927 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02002928 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2929
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002930 int ret;
2931 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002932 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002933
2934 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2935
2936 if (req->n_ssids) {
2937 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002938 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002939 }
2940
2941 mutex_lock(&wl->mutex);
2942
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002943 if (wl->state == WL1271_STATE_OFF) {
2944 /*
2945 * We cannot return -EBUSY here because cfg80211 will expect
2946 * a call to ieee80211_scan_completed if we do - in this case
2947 * there won't be any call.
2948 */
2949 ret = -EAGAIN;
2950 goto out;
2951 }
2952
Ido Yariva6208652011-03-01 15:14:41 +02002953 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002954 if (ret < 0)
2955 goto out;
2956
Eliad Peller251c1772011-08-14 13:17:17 +03002957 /* cancel ROC before scanning */
2958 if (wl12xx_is_roc(wl)) {
2959 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2960 /* don't allow scanning right now */
2961 ret = -EBUSY;
2962 goto out_sleep;
2963 }
Eliad Peller7edebf52011-10-05 11:55:52 +02002964 wl12xx_croc(wl, wlvif->dev_role_id);
2965 wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002966 }
2967
Eliad Peller784f6942011-10-05 11:55:39 +02002968 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002969out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002970 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002971out:
2972 mutex_unlock(&wl->mutex);
2973
2974 return ret;
2975}
2976
Eliad Peller73ecce32011-06-27 13:06:45 +03002977static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2978 struct ieee80211_vif *vif)
2979{
2980 struct wl1271 *wl = hw->priv;
2981 int ret;
2982
2983 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2984
2985 mutex_lock(&wl->mutex);
2986
2987 if (wl->state == WL1271_STATE_OFF)
2988 goto out;
2989
2990 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2991 goto out;
2992
2993 ret = wl1271_ps_elp_wakeup(wl);
2994 if (ret < 0)
2995 goto out;
2996
2997 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2998 ret = wl1271_scan_stop(wl);
2999 if (ret < 0)
3000 goto out_sleep;
3001 }
3002 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3003 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003004 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003005 wl->scan.req = NULL;
3006 ieee80211_scan_completed(wl->hw, true);
3007
3008out_sleep:
3009 wl1271_ps_elp_sleep(wl);
3010out:
3011 mutex_unlock(&wl->mutex);
3012
3013 cancel_delayed_work_sync(&wl->scan_complete_work);
3014}
3015
Luciano Coelho33c2c062011-05-10 14:46:02 +03003016static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3017 struct ieee80211_vif *vif,
3018 struct cfg80211_sched_scan_request *req,
3019 struct ieee80211_sched_scan_ies *ies)
3020{
3021 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003022 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003023 int ret;
3024
3025 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3026
3027 mutex_lock(&wl->mutex);
3028
3029 ret = wl1271_ps_elp_wakeup(wl);
3030 if (ret < 0)
3031 goto out;
3032
Eliad Peller536129c2011-10-05 11:55:45 +02003033 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003034 if (ret < 0)
3035 goto out_sleep;
3036
Eliad Peller536129c2011-10-05 11:55:45 +02003037 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003038 if (ret < 0)
3039 goto out_sleep;
3040
3041 wl->sched_scanning = true;
3042
3043out_sleep:
3044 wl1271_ps_elp_sleep(wl);
3045out:
3046 mutex_unlock(&wl->mutex);
3047 return ret;
3048}
3049
3050static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3051 struct ieee80211_vif *vif)
3052{
3053 struct wl1271 *wl = hw->priv;
3054 int ret;
3055
3056 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3057
3058 mutex_lock(&wl->mutex);
3059
3060 ret = wl1271_ps_elp_wakeup(wl);
3061 if (ret < 0)
3062 goto out;
3063
3064 wl1271_scan_sched_scan_stop(wl);
3065
3066 wl1271_ps_elp_sleep(wl);
3067out:
3068 mutex_unlock(&wl->mutex);
3069}
3070
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003071static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3072{
3073 struct wl1271 *wl = hw->priv;
3074 int ret = 0;
3075
3076 mutex_lock(&wl->mutex);
3077
3078 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3079 ret = -EAGAIN;
3080 goto out;
3081 }
3082
Ido Yariva6208652011-03-01 15:14:41 +02003083 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003084 if (ret < 0)
3085 goto out;
3086
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003087 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003088 if (ret < 0)
3089 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3090
3091 wl1271_ps_elp_sleep(wl);
3092
3093out:
3094 mutex_unlock(&wl->mutex);
3095
3096 return ret;
3097}
3098
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003099static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3100{
3101 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003102 struct ieee80211_vif *vif = wl->vif;
3103 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003104 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003105
3106 mutex_lock(&wl->mutex);
3107
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003108 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3109 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003110 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003111 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003112
Ido Yariva6208652011-03-01 15:14:41 +02003113 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003114 if (ret < 0)
3115 goto out;
3116
Eliad Peller0603d892011-10-05 11:55:51 +02003117 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003118 if (ret < 0)
3119 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
3120
3121 wl1271_ps_elp_sleep(wl);
3122
3123out:
3124 mutex_unlock(&wl->mutex);
3125
3126 return ret;
3127}
3128
Eliad Peller1fe9f162011-10-05 11:55:48 +02003129static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003130 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003131{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003132 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003133 u8 ssid_len;
3134 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3135 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003136
Eliad Peller889cb362011-05-01 09:56:45 +03003137 if (!ptr) {
3138 wl1271_error("No SSID in IEs!");
3139 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003140 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003141
Eliad Peller889cb362011-05-01 09:56:45 +03003142 ssid_len = ptr[1];
3143 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3144 wl1271_error("SSID is too long!");
3145 return -EINVAL;
3146 }
3147
Eliad Peller1fe9f162011-10-05 11:55:48 +02003148 wlvif->ssid_len = ssid_len;
3149 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003150 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003151}
3152
Eliad Pellerd48055d2011-09-15 12:07:04 +03003153static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3154{
3155 int len;
3156 const u8 *next, *end = skb->data + skb->len;
3157 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3158 skb->len - ieoffset);
3159 if (!ie)
3160 return;
3161 len = ie[1] + 2;
3162 next = ie + len;
3163 memmove(ie, next, end - next);
3164 skb_trim(skb, skb->len - len);
3165}
3166
Eliad Peller26b4bf22011-09-15 12:07:05 +03003167static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3168 unsigned int oui, u8 oui_type,
3169 int ieoffset)
3170{
3171 int len;
3172 const u8 *next, *end = skb->data + skb->len;
3173 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3174 skb->data + ieoffset,
3175 skb->len - ieoffset);
3176 if (!ie)
3177 return;
3178 len = ie[1] + 2;
3179 next = ie + len;
3180 memmove(ie, next, end - next);
3181 skb_trim(skb, skb->len - len);
3182}
3183
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003184static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
Eliad Peller1fe9f162011-10-05 11:55:48 +02003185 struct ieee80211_vif *vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003186 u8 *probe_rsp_data,
3187 size_t probe_rsp_len,
3188 u32 rates)
3189{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003190 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3191 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003192 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3193 int ssid_ie_offset, ie_offset, templ_len;
3194 const u8 *ptr;
3195
3196 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003197 if (wlvif->ssid_len > 0)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003198 return wl1271_cmd_template_set(wl,
3199 CMD_TEMPL_AP_PROBE_RESPONSE,
3200 probe_rsp_data,
3201 probe_rsp_len, 0,
3202 rates);
3203
3204 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3205 wl1271_error("probe_rsp template too big");
3206 return -EINVAL;
3207 }
3208
3209 /* start searching from IE offset */
3210 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3211
3212 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3213 probe_rsp_len - ie_offset);
3214 if (!ptr) {
3215 wl1271_error("No SSID in beacon!");
3216 return -EINVAL;
3217 }
3218
3219 ssid_ie_offset = ptr - probe_rsp_data;
3220 ptr += (ptr[1] + 2);
3221
3222 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3223
3224 /* insert SSID from bss_conf */
3225 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3226 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3227 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3228 bss_conf->ssid, bss_conf->ssid_len);
3229 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3230
3231 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3232 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3233 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3234
3235 return wl1271_cmd_template_set(wl,
3236 CMD_TEMPL_AP_PROBE_RESPONSE,
3237 probe_rsp_templ,
3238 templ_len, 0,
3239 rates);
3240}
3241
Arik Nemtsove78a2872010-10-16 19:07:21 +02003242static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003243 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003244 struct ieee80211_bss_conf *bss_conf,
3245 u32 changed)
3246{
Eliad Peller0603d892011-10-05 11:55:51 +02003247 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003248 int ret = 0;
3249
3250 if (changed & BSS_CHANGED_ERP_SLOT) {
3251 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003252 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003253 else
Eliad Peller0603d892011-10-05 11:55:51 +02003254 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003255 if (ret < 0) {
3256 wl1271_warning("Set slot time failed %d", ret);
3257 goto out;
3258 }
3259 }
3260
3261 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3262 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003263 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003264 else
Eliad Peller0603d892011-10-05 11:55:51 +02003265 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003266 }
3267
3268 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3269 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003270 ret = wl1271_acx_cts_protect(wl, wlvif,
3271 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003272 else
Eliad Peller0603d892011-10-05 11:55:51 +02003273 ret = wl1271_acx_cts_protect(wl, wlvif,
3274 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003275 if (ret < 0) {
3276 wl1271_warning("Set ctsprotect failed %d", ret);
3277 goto out;
3278 }
3279 }
3280
3281out:
3282 return ret;
3283}
3284
3285static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3286 struct ieee80211_vif *vif,
3287 struct ieee80211_bss_conf *bss_conf,
3288 u32 changed)
3289{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003290 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003291 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003292 int ret = 0;
3293
3294 if ((changed & BSS_CHANGED_BEACON_INT)) {
3295 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3296 bss_conf->beacon_int);
3297
Eliad Peller6a899792011-10-05 11:55:58 +02003298 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003299 }
3300
3301 if ((changed & BSS_CHANGED_BEACON)) {
3302 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003303 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003304 int ieoffset = offsetof(struct ieee80211_mgmt,
3305 u.beacon.variable);
3306 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3307 u16 tmpl_id;
3308
3309 if (!beacon)
3310 goto out;
3311
3312 wl1271_debug(DEBUG_MASTER, "beacon updated");
3313
Eliad Peller1fe9f162011-10-05 11:55:48 +02003314 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003315 if (ret < 0) {
3316 dev_kfree_skb(beacon);
3317 goto out;
3318 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003319 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003320 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3321 CMD_TEMPL_BEACON;
3322 ret = wl1271_cmd_template_set(wl, tmpl_id,
3323 beacon->data,
3324 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003325 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003326 if (ret < 0) {
3327 dev_kfree_skb(beacon);
3328 goto out;
3329 }
3330
Eliad Pellerd48055d2011-09-15 12:07:04 +03003331 /* remove TIM ie from probe response */
3332 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3333
Eliad Peller26b4bf22011-09-15 12:07:05 +03003334 /*
3335 * remove p2p ie from probe response.
3336 * the fw reponds to probe requests that don't include
3337 * the p2p ie. probe requests with p2p ie will be passed,
3338 * and will be responded by the supplicant (the spec
3339 * forbids including the p2p ie when responding to probe
3340 * requests that didn't include it).
3341 */
3342 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3343 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3344
Arik Nemtsove78a2872010-10-16 19:07:21 +02003345 hdr = (struct ieee80211_hdr *) beacon->data;
3346 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3347 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003348 if (is_ap)
Eliad Peller1fe9f162011-10-05 11:55:48 +02003349 ret = wl1271_ap_set_probe_resp_tmpl(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003350 beacon->data,
3351 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003352 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003353 else
3354 ret = wl1271_cmd_template_set(wl,
3355 CMD_TEMPL_PROBE_RESPONSE,
3356 beacon->data,
3357 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003358 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003359 dev_kfree_skb(beacon);
3360 if (ret < 0)
3361 goto out;
3362 }
3363
3364out:
3365 return ret;
3366}
3367
3368/* AP mode changes */
3369static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003370 struct ieee80211_vif *vif,
3371 struct ieee80211_bss_conf *bss_conf,
3372 u32 changed)
3373{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003374 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003375 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003376
Arik Nemtsove78a2872010-10-16 19:07:21 +02003377 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3378 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003379
Eliad Peller87fbcb02011-10-05 11:55:41 +02003380 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003381 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003382 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003383 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003384
Eliad Peller87fbcb02011-10-05 11:55:41 +02003385 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003386 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003387 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003388 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003389 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003390
Eliad Peller784f6942011-10-05 11:55:39 +02003391 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003392 if (ret < 0)
3393 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003394 }
3395
Arik Nemtsove78a2872010-10-16 19:07:21 +02003396 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3397 if (ret < 0)
3398 goto out;
3399
3400 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3401 if (bss_conf->enable_beacon) {
3402 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003403 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003404 if (ret < 0)
3405 goto out;
3406
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003407 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003408 if (ret < 0)
3409 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003410
3411 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3412 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003413 }
3414 } else {
3415 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003416 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003417 if (ret < 0)
3418 goto out;
3419
3420 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3421 wl1271_debug(DEBUG_AP, "stopped AP");
3422 }
3423 }
3424 }
3425
Eliad Peller0603d892011-10-05 11:55:51 +02003426 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003427 if (ret < 0)
3428 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003429
3430 /* Handle HT information change */
3431 if ((changed & BSS_CHANGED_HT) &&
3432 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003433 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003434 bss_conf->ht_operation_mode);
3435 if (ret < 0) {
3436 wl1271_warning("Set ht information failed %d", ret);
3437 goto out;
3438 }
3439 }
3440
Arik Nemtsove78a2872010-10-16 19:07:21 +02003441out:
3442 return;
3443}
3444
3445/* STA/IBSS mode changes */
3446static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3447 struct ieee80211_vif *vif,
3448 struct ieee80211_bss_conf *bss_conf,
3449 u32 changed)
3450{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003451 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003452 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003453 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003454 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003455 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003456 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003457 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003458 bool sta_exists = false;
3459 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003460
3461 if (is_ibss) {
3462 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3463 changed);
3464 if (ret < 0)
3465 goto out;
3466 }
3467
Eliad Peller227e81e2011-08-14 13:17:26 +03003468 if (changed & BSS_CHANGED_IBSS) {
3469 if (bss_conf->ibss_joined) {
3470 set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
3471 ibss_joined = true;
3472 } else {
3473 if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
3474 &wl->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003475 wl1271_unjoin(wl, wlvif);
Eliad Peller7edebf52011-10-05 11:55:52 +02003476 wl12xx_cmd_role_start_dev(wl, wlvif);
3477 wl12xx_roc(wl, wlvif->dev_role_id);
Eliad Peller227e81e2011-08-14 13:17:26 +03003478 }
3479 }
3480 }
3481
3482 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003483 do_join = true;
3484
3485 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003486 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003487 do_join = true;
3488
Eliad Peller227e81e2011-08-14 13:17:26 +03003489 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003490 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3491 bss_conf->enable_beacon ? "enabled" : "disabled");
3492
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003493 do_join = true;
3494 }
3495
Arik Nemtsove78a2872010-10-16 19:07:21 +02003496 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003497 bool enable = false;
3498 if (bss_conf->cqm_rssi_thold)
3499 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003500 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003501 bss_conf->cqm_rssi_thold,
3502 bss_conf->cqm_rssi_hyst);
3503 if (ret < 0)
3504 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003505 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003506 }
3507
Eliad Pellercdf09492011-10-05 11:55:44 +02003508 if (changed & BSS_CHANGED_BSSID)
3509 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003510 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003511 if (ret < 0)
3512 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003513
Eliad Peller784f6942011-10-05 11:55:39 +02003514 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003515 if (ret < 0)
3516 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003517
Eliad Pellerfa287b82010-12-26 09:27:50 +01003518 /* Need to update the BSSID (for filtering etc) */
3519 do_join = true;
3520 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003521
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003522 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3523 rcu_read_lock();
3524 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3525 if (!sta)
3526 goto sta_not_found;
3527
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003528 /* save the supp_rates of the ap */
3529 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3530 if (sta->ht_cap.ht_supported)
3531 sta_rate_set |=
3532 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003533 sta_ht_cap = sta->ht_cap;
3534 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003535
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003536sta_not_found:
3537 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003538 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003539
Arik Nemtsove78a2872010-10-16 19:07:21 +02003540 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003541 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003542 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003543 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003544 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003545 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003546
Eliad Peller74ec8392011-10-05 11:56:02 +02003547 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003548
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003549 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003550 * use basic rates from AP, and determine lowest rate
3551 * to use with control frames.
3552 */
3553 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003554 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003555 wl1271_tx_enabled_rates_get(wl, rates,
3556 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003557 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003558 wl1271_tx_min_rate_get(wl,
3559 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003560 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003561 wlvif->rate_set =
3562 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003563 sta_rate_set,
3564 wl->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003565 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003566 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003567 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003568
3569 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003570 * with wl1271, we don't need to update the
3571 * beacon_int and dtim_period, because the firmware
3572 * updates it by itself when the first beacon is
3573 * received after a join.
3574 */
Eliad Peller6840e372011-10-05 11:55:50 +02003575 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003576 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003577 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003578
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003579 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003580 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003581 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003582 dev_kfree_skb(wlvif->probereq);
3583 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003584 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003585 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003586 ieoffset = offsetof(struct ieee80211_mgmt,
3587 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003588 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003589
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003590 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003591 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003592 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003593 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003594 } else {
3595 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003596 bool was_assoc =
3597 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3598 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003599 bool was_ifup =
3600 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3601 &wl->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003602 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003603
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003604 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003605 dev_kfree_skb(wlvif->probereq);
3606 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003607
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003608 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003609 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003610
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003611 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003612 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003613 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003614 wl1271_tx_min_rate_get(wl,
3615 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003616 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003617 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003618 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003619
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003620 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003621 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003622
3623 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003624 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003625 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003626 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003627
3628 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003629 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003630 u32 conf_flags = wl->hw->conf.flags;
3631 /*
3632 * we might have to disable roc, if there was
3633 * no IF_OPER_UP notification.
3634 */
3635 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003636 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003637 if (ret < 0)
3638 goto out;
3639 }
3640 /*
3641 * (we also need to disable roc in case of
3642 * roaming on the same channel. until we will
3643 * have a better flow...)
3644 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003645 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3646 ret = wl12xx_croc(wl,
3647 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003648 if (ret < 0)
3649 goto out;
3650 }
3651
Eliad Peller0603d892011-10-05 11:55:51 +02003652 wl1271_unjoin(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003653 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
Eliad Peller7edebf52011-10-05 11:55:52 +02003654 wl12xx_cmd_role_start_dev(wl, wlvif);
3655 wl12xx_roc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003656 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003657 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003658 }
3659 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003660
Eliad Pellerd192d262011-05-24 14:33:08 +03003661 if (changed & BSS_CHANGED_IBSS) {
3662 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3663 bss_conf->ibss_joined);
3664
3665 if (bss_conf->ibss_joined) {
3666 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003667 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003668 wl1271_tx_enabled_rates_get(wl, rates,
3669 wl->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003670 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003671 wl1271_tx_min_rate_get(wl,
3672 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003673
Shahar Levi06b660e2011-09-05 13:54:36 +03003674 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003675 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3676 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003677 if (ret < 0)
3678 goto out;
3679 }
3680 }
3681
Eliad Peller0603d892011-10-05 11:55:51 +02003682 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003683 if (ret < 0)
3684 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003685
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003686 if (changed & BSS_CHANGED_ARP_FILTER) {
3687 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003688 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003689
Eliad Pellerc5312772010-12-09 11:31:27 +02003690 if (bss_conf->arp_addr_cnt == 1 &&
3691 bss_conf->arp_filter_enabled) {
3692 /*
3693 * The template should have been configured only upon
3694 * association. however, it seems that the correct ip
3695 * isn't being set (when sending), so we have to
3696 * reconfigure the template upon every ip change.
3697 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003698 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003699 if (ret < 0) {
3700 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003701 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003702 }
3703
Eliad Peller0603d892011-10-05 11:55:51 +02003704 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003705 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003706 addr);
3707 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003708 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003709
3710 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003711 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003712 }
3713
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003714 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003715 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003716 if (ret < 0) {
3717 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003718 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003719 }
Eliad Peller251c1772011-08-14 13:17:17 +03003720
3721 /* ROC until connected (after EAPOL exchange) */
3722 if (!is_ibss) {
Eliad Peller0603d892011-10-05 11:55:51 +02003723 ret = wl12xx_roc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003724 if (ret < 0)
3725 goto out;
3726
3727 wl1271_check_operstate(wl,
3728 ieee80211_get_operstate(vif));
3729 }
3730 /*
3731 * stop device role if started (we might already be in
3732 * STA role). TODO: make it better.
3733 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003734 if (wlvif->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3735 ret = wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003736 if (ret < 0)
3737 goto out;
3738
Eliad Peller7edebf52011-10-05 11:55:52 +02003739 ret = wl12xx_cmd_role_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003740 if (ret < 0)
3741 goto out;
3742 }
Eliad Peller05dba352011-08-23 16:37:01 +03003743
3744 /* If we want to go in PSM but we're not there yet */
3745 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3746 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
3747 enum wl1271_cmd_ps_mode mode;
3748
3749 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003750 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003751 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003752 true);
3753 if (ret < 0)
3754 goto out;
3755 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003756 }
3757
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003758 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003759 if (sta_exists) {
3760 if ((changed & BSS_CHANGED_HT) &&
3761 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003762 ret = wl1271_acx_set_ht_capabilities(wl,
3763 &sta_ht_cap,
3764 true,
Eliad Peller154da672011-10-05 11:55:53 +02003765 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003766 if (ret < 0) {
3767 wl1271_warning("Set ht cap true failed %d",
3768 ret);
3769 goto out;
3770 }
3771 }
3772 /* handle new association without HT and disassociation */
3773 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003774 ret = wl1271_acx_set_ht_capabilities(wl,
3775 &sta_ht_cap,
3776 false,
Eliad Peller154da672011-10-05 11:55:53 +02003777 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003778 if (ret < 0) {
3779 wl1271_warning("Set ht cap false failed %d",
3780 ret);
3781 goto out;
3782 }
3783 }
3784 }
3785
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003786 /* Handle HT information change. Done after join. */
3787 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003788 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003789 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003790 bss_conf->ht_operation_mode);
3791 if (ret < 0) {
3792 wl1271_warning("Set ht information failed %d", ret);
3793 goto out;
3794 }
3795 }
3796
Arik Nemtsove78a2872010-10-16 19:07:21 +02003797out:
3798 return;
3799}
3800
3801static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3802 struct ieee80211_vif *vif,
3803 struct ieee80211_bss_conf *bss_conf,
3804 u32 changed)
3805{
3806 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003807 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3808 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003809 int ret;
3810
3811 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3812 (int)changed);
3813
3814 mutex_lock(&wl->mutex);
3815
3816 if (unlikely(wl->state == WL1271_STATE_OFF))
3817 goto out;
3818
Ido Yariva6208652011-03-01 15:14:41 +02003819 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003820 if (ret < 0)
3821 goto out;
3822
3823 if (is_ap)
3824 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3825 else
3826 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3827
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003828 wl1271_ps_elp_sleep(wl);
3829
3830out:
3831 mutex_unlock(&wl->mutex);
3832}
3833
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003834static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3835 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003836 const struct ieee80211_tx_queue_params *params)
3837{
3838 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003839 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003840 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003841 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003842
3843 mutex_lock(&wl->mutex);
3844
3845 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3846
Kalle Valo4695dc92010-03-18 12:26:38 +02003847 if (params->uapsd)
3848 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3849 else
3850 ps_scheme = CONF_PS_SCHEME_LEGACY;
3851
Arik Nemtsov488fc542010-10-16 20:33:45 +02003852 if (wl->state == WL1271_STATE_OFF) {
3853 /*
3854 * If the state is off, the parameters will be recorded and
3855 * configured on init. This happens in AP-mode.
3856 */
3857 struct conf_tx_ac_category *conf_ac =
3858 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3859 struct conf_tx_tid *conf_tid =
3860 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3861
3862 conf_ac->ac = wl1271_tx_get_queue(queue);
3863 conf_ac->cw_min = (u8)params->cw_min;
3864 conf_ac->cw_max = params->cw_max;
3865 conf_ac->aifsn = params->aifs;
3866 conf_ac->tx_op_limit = params->txop << 5;
3867
3868 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3869 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3870 conf_tid->tsid = wl1271_tx_get_queue(queue);
3871 conf_tid->ps_scheme = ps_scheme;
3872 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3873 conf_tid->apsd_conf[0] = 0;
3874 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003875 goto out;
3876 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003877
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003878 ret = wl1271_ps_elp_wakeup(wl);
3879 if (ret < 0)
3880 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003881
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003882 /*
3883 * the txop is confed in units of 32us by the mac80211,
3884 * we need us
3885 */
Eliad Peller0603d892011-10-05 11:55:51 +02003886 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003887 params->cw_min, params->cw_max,
3888 params->aifs, params->txop << 5);
3889 if (ret < 0)
3890 goto out_sleep;
3891
Eliad Peller0603d892011-10-05 11:55:51 +02003892 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003893 CONF_CHANNEL_TYPE_EDCF,
3894 wl1271_tx_get_queue(queue),
3895 ps_scheme, CONF_ACK_POLICY_LEGACY,
3896 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003897
3898out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003899 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003900
3901out:
3902 mutex_unlock(&wl->mutex);
3903
3904 return ret;
3905}
3906
Eliad Peller37a41b42011-09-21 14:06:11 +03003907static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
3908 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003909{
3910
3911 struct wl1271 *wl = hw->priv;
3912 u64 mactime = ULLONG_MAX;
3913 int ret;
3914
3915 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3916
3917 mutex_lock(&wl->mutex);
3918
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003919 if (unlikely(wl->state == WL1271_STATE_OFF))
3920 goto out;
3921
Ido Yariva6208652011-03-01 15:14:41 +02003922 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003923 if (ret < 0)
3924 goto out;
3925
3926 ret = wl1271_acx_tsf_info(wl, &mactime);
3927 if (ret < 0)
3928 goto out_sleep;
3929
3930out_sleep:
3931 wl1271_ps_elp_sleep(wl);
3932
3933out:
3934 mutex_unlock(&wl->mutex);
3935 return mactime;
3936}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003937
John W. Linvilleece550d2010-07-28 16:41:06 -04003938static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3939 struct survey_info *survey)
3940{
3941 struct wl1271 *wl = hw->priv;
3942 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003943
John W. Linvilleece550d2010-07-28 16:41:06 -04003944 if (idx != 0)
3945 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003946
John W. Linvilleece550d2010-07-28 16:41:06 -04003947 survey->channel = conf->channel;
3948 survey->filled = SURVEY_INFO_NOISE_DBM;
3949 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003950
John W. Linvilleece550d2010-07-28 16:41:06 -04003951 return 0;
3952}
3953
Arik Nemtsov409622e2011-02-23 00:22:29 +02003954static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02003955 struct wl12xx_vif *wlvif,
3956 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003957{
3958 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02003959 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003960
Eliad Pellerc7ffb902011-10-05 11:56:05 +02003961
3962 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003963 wl1271_warning("could not allocate HLID - too much stations");
3964 return -EBUSY;
3965 }
3966
3967 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02003968 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
3969 if (ret < 0) {
3970 wl1271_warning("could not allocate HLID - too many links");
3971 return -EBUSY;
3972 }
3973
3974 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003975 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03003976 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003977 return 0;
3978}
3979
Eliad Pellerc7ffb902011-10-05 11:56:05 +02003980void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003981{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02003982 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03003983 return;
3984
Eliad Pellerc7ffb902011-10-05 11:56:05 +02003985 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003986 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003987 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003988 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003989 __clear_bit(hlid, &wl->ap_ps_map);
3990 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02003991 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03003992 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003993}
3994
3995static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3996 struct ieee80211_vif *vif,
3997 struct ieee80211_sta *sta)
3998{
3999 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004000 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004001 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004002 int ret = 0;
4003 u8 hlid;
4004
4005 mutex_lock(&wl->mutex);
4006
4007 if (unlikely(wl->state == WL1271_STATE_OFF))
4008 goto out;
4009
Eliad Peller536129c2011-10-05 11:55:45 +02004010 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004011 goto out;
4012
4013 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4014
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004015 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004016 if (ret < 0)
4017 goto out;
4018
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004019 wl_sta = (struct wl1271_station *)sta->drv_priv;
4020 hlid = wl_sta->hlid;
4021
Ido Yariva6208652011-03-01 15:14:41 +02004022 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004023 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004024 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004025
Eliad Pellerc690ec82011-08-14 13:17:07 +03004026 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004027 if (ret < 0)
4028 goto out_sleep;
4029
Eliad Pellerb67476e2011-08-14 13:17:23 +03004030 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4031 if (ret < 0)
4032 goto out_sleep;
4033
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004034 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4035 if (ret < 0)
4036 goto out_sleep;
4037
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004038out_sleep:
4039 wl1271_ps_elp_sleep(wl);
4040
Arik Nemtsov409622e2011-02-23 00:22:29 +02004041out_free_sta:
4042 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004043 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004044
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004045out:
4046 mutex_unlock(&wl->mutex);
4047 return ret;
4048}
4049
4050static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4051 struct ieee80211_vif *vif,
4052 struct ieee80211_sta *sta)
4053{
4054 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004055 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004056 struct wl1271_station *wl_sta;
4057 int ret = 0, id;
4058
4059 mutex_lock(&wl->mutex);
4060
4061 if (unlikely(wl->state == WL1271_STATE_OFF))
4062 goto out;
4063
Eliad Peller536129c2011-10-05 11:55:45 +02004064 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004065 goto out;
4066
4067 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4068
4069 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004070 id = wl_sta->hlid;
4071 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004072 goto out;
4073
Ido Yariva6208652011-03-01 15:14:41 +02004074 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004075 if (ret < 0)
4076 goto out;
4077
Eliad Pellerc690ec82011-08-14 13:17:07 +03004078 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004079 if (ret < 0)
4080 goto out_sleep;
4081
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004082 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004083
4084out_sleep:
4085 wl1271_ps_elp_sleep(wl);
4086
4087out:
4088 mutex_unlock(&wl->mutex);
4089 return ret;
4090}
4091
Luciano Coelho4623ec72011-03-21 19:26:41 +02004092static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4093 struct ieee80211_vif *vif,
4094 enum ieee80211_ampdu_mlme_action action,
4095 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4096 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004097{
4098 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004099 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004100 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004101 u8 hlid, *ba_bitmap;
4102
4103 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4104 tid);
4105
4106 /* sanity check - the fields in FW are only 8bits wide */
4107 if (WARN_ON(tid > 0xFF))
4108 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004109
4110 mutex_lock(&wl->mutex);
4111
4112 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4113 ret = -EAGAIN;
4114 goto out;
4115 }
4116
Eliad Peller536129c2011-10-05 11:55:45 +02004117 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004118 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004119 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004120 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004121 struct wl1271_station *wl_sta;
4122
4123 wl_sta = (struct wl1271_station *)sta->drv_priv;
4124 hlid = wl_sta->hlid;
4125 ba_bitmap = &wl->links[hlid].ba_bitmap;
4126 } else {
4127 ret = -EINVAL;
4128 goto out;
4129 }
4130
Ido Yariva6208652011-03-01 15:14:41 +02004131 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004132 if (ret < 0)
4133 goto out;
4134
Shahar Levi70559a02011-05-22 16:10:22 +03004135 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4136 tid, action);
4137
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004138 switch (action) {
4139 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004140 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004141 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004142 break;
4143 }
4144
4145 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4146 ret = -EBUSY;
4147 wl1271_error("exceeded max RX BA sessions");
4148 break;
4149 }
4150
4151 if (*ba_bitmap & BIT(tid)) {
4152 ret = -EINVAL;
4153 wl1271_error("cannot enable RX BA session on active "
4154 "tid: %d", tid);
4155 break;
4156 }
4157
4158 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4159 hlid);
4160 if (!ret) {
4161 *ba_bitmap |= BIT(tid);
4162 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004163 }
4164 break;
4165
4166 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004167 if (!(*ba_bitmap & BIT(tid))) {
4168 ret = -EINVAL;
4169 wl1271_error("no active RX BA session on tid: %d",
4170 tid);
4171 break;
4172 }
4173
4174 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4175 hlid);
4176 if (!ret) {
4177 *ba_bitmap &= ~BIT(tid);
4178 wl->ba_rx_session_count--;
4179 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004180 break;
4181
4182 /*
4183 * The BA initiator session management in FW independently.
4184 * Falling break here on purpose for all TX APDU commands.
4185 */
4186 case IEEE80211_AMPDU_TX_START:
4187 case IEEE80211_AMPDU_TX_STOP:
4188 case IEEE80211_AMPDU_TX_OPERATIONAL:
4189 ret = -EINVAL;
4190 break;
4191
4192 default:
4193 wl1271_error("Incorrect ampdu action id=%x\n", action);
4194 ret = -EINVAL;
4195 }
4196
4197 wl1271_ps_elp_sleep(wl);
4198
4199out:
4200 mutex_unlock(&wl->mutex);
4201
4202 return ret;
4203}
4204
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004205static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4206 struct ieee80211_vif *vif,
4207 const struct cfg80211_bitrate_mask *mask)
4208{
Eliad Peller83587502011-10-10 10:12:53 +02004209 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004210 struct wl1271 *wl = hw->priv;
4211 int i;
4212
4213 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4214 mask->control[NL80211_BAND_2GHZ].legacy,
4215 mask->control[NL80211_BAND_5GHZ].legacy);
4216
4217 mutex_lock(&wl->mutex);
4218
4219 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004220 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004221 wl1271_tx_enabled_rates_get(wl,
4222 mask->control[i].legacy,
4223 i);
4224 mutex_unlock(&wl->mutex);
4225
4226 return 0;
4227}
4228
Shahar Levi6d158ff2011-09-08 13:01:33 +03004229static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4230 struct ieee80211_channel_switch *ch_switch)
4231{
4232 struct wl1271 *wl = hw->priv;
4233 int ret;
4234
4235 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4236
4237 mutex_lock(&wl->mutex);
4238
4239 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4240 mutex_unlock(&wl->mutex);
4241 ieee80211_chswitch_done(wl->vif, false);
4242 return;
4243 }
4244
4245 ret = wl1271_ps_elp_wakeup(wl);
4246 if (ret < 0)
4247 goto out;
4248
4249 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
4250
4251 if (!ret)
4252 set_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags);
4253
4254 wl1271_ps_elp_sleep(wl);
4255
4256out:
4257 mutex_unlock(&wl->mutex);
4258}
4259
Arik Nemtsov33437892011-04-26 23:35:39 +03004260static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4261{
4262 struct wl1271 *wl = hw->priv;
4263 bool ret = false;
4264
4265 mutex_lock(&wl->mutex);
4266
4267 if (unlikely(wl->state == WL1271_STATE_OFF))
4268 goto out;
4269
4270 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004271 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004272out:
4273 mutex_unlock(&wl->mutex);
4274
4275 return ret;
4276}
4277
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004278/* can't be const, mac80211 writes to this */
4279static struct ieee80211_rate wl1271_rates[] = {
4280 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004281 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4282 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004283 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004284 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4285 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004286 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4287 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004288 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4289 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004290 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4291 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004292 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4293 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004294 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4295 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004296 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4297 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004298 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004299 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4300 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004301 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004302 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4303 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004304 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004305 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4306 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004307 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004308 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4309 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004310 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004311 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4312 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004313 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004314 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4315 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004316 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004317 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4318 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004319};
4320
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004321/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004322static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004323 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004324 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004325 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4326 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4327 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004328 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004329 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4330 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4331 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004332 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004333 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4334 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4335 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004336 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004337};
4338
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004339/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004340static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004341 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004342 7, /* CONF_HW_RXTX_RATE_MCS7 */
4343 6, /* CONF_HW_RXTX_RATE_MCS6 */
4344 5, /* CONF_HW_RXTX_RATE_MCS5 */
4345 4, /* CONF_HW_RXTX_RATE_MCS4 */
4346 3, /* CONF_HW_RXTX_RATE_MCS3 */
4347 2, /* CONF_HW_RXTX_RATE_MCS2 */
4348 1, /* CONF_HW_RXTX_RATE_MCS1 */
4349 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004350
4351 11, /* CONF_HW_RXTX_RATE_54 */
4352 10, /* CONF_HW_RXTX_RATE_48 */
4353 9, /* CONF_HW_RXTX_RATE_36 */
4354 8, /* CONF_HW_RXTX_RATE_24 */
4355
4356 /* TI-specific rate */
4357 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4358
4359 7, /* CONF_HW_RXTX_RATE_18 */
4360 6, /* CONF_HW_RXTX_RATE_12 */
4361 3, /* CONF_HW_RXTX_RATE_11 */
4362 5, /* CONF_HW_RXTX_RATE_9 */
4363 4, /* CONF_HW_RXTX_RATE_6 */
4364 2, /* CONF_HW_RXTX_RATE_5_5 */
4365 1, /* CONF_HW_RXTX_RATE_2 */
4366 0 /* CONF_HW_RXTX_RATE_1 */
4367};
4368
Shahar Levie8b03a22010-10-13 16:09:39 +02004369/* 11n STA capabilities */
4370#define HW_RX_HIGHEST_RATE 72
4371
Shahar Levi00d20102010-11-08 11:20:10 +00004372#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004373 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4374 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004375 .ht_supported = true, \
4376 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4377 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4378 .mcs = { \
4379 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4380 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4381 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4382 }, \
4383}
4384
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004385/* can't be const, mac80211 writes to this */
4386static struct ieee80211_supported_band wl1271_band_2ghz = {
4387 .channels = wl1271_channels,
4388 .n_channels = ARRAY_SIZE(wl1271_channels),
4389 .bitrates = wl1271_rates,
4390 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004391 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004392};
4393
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004394/* 5 GHz data rates for WL1273 */
4395static struct ieee80211_rate wl1271_rates_5ghz[] = {
4396 { .bitrate = 60,
4397 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4398 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4399 { .bitrate = 90,
4400 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4401 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4402 { .bitrate = 120,
4403 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4404 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4405 { .bitrate = 180,
4406 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4407 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4408 { .bitrate = 240,
4409 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4410 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4411 { .bitrate = 360,
4412 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4413 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4414 { .bitrate = 480,
4415 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4416 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4417 { .bitrate = 540,
4418 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4419 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4420};
4421
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004422/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004423static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004424 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4425 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4426 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4427 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4428 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4429 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4430 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4431 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4432 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4433 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4434 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4435 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4436 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4437 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4438 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4439 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4440 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4441 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4442 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4443 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4444 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4445 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4446 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4447 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4448 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4449 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4450 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4451 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4452 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4453 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4454 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4455 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4456 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4457 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004458};
4459
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004460/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004461static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004462 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004463 7, /* CONF_HW_RXTX_RATE_MCS7 */
4464 6, /* CONF_HW_RXTX_RATE_MCS6 */
4465 5, /* CONF_HW_RXTX_RATE_MCS5 */
4466 4, /* CONF_HW_RXTX_RATE_MCS4 */
4467 3, /* CONF_HW_RXTX_RATE_MCS3 */
4468 2, /* CONF_HW_RXTX_RATE_MCS2 */
4469 1, /* CONF_HW_RXTX_RATE_MCS1 */
4470 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004471
4472 7, /* CONF_HW_RXTX_RATE_54 */
4473 6, /* CONF_HW_RXTX_RATE_48 */
4474 5, /* CONF_HW_RXTX_RATE_36 */
4475 4, /* CONF_HW_RXTX_RATE_24 */
4476
4477 /* TI-specific rate */
4478 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4479
4480 3, /* CONF_HW_RXTX_RATE_18 */
4481 2, /* CONF_HW_RXTX_RATE_12 */
4482 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4483 1, /* CONF_HW_RXTX_RATE_9 */
4484 0, /* CONF_HW_RXTX_RATE_6 */
4485 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4486 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4487 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4488};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004489
4490static struct ieee80211_supported_band wl1271_band_5ghz = {
4491 .channels = wl1271_channels_5ghz,
4492 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4493 .bitrates = wl1271_rates_5ghz,
4494 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004495 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004496};
4497
Tobias Klausera0ea9492010-05-20 10:38:11 +02004498static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004499 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4500 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4501};
4502
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004503static const struct ieee80211_ops wl1271_ops = {
4504 .start = wl1271_op_start,
4505 .stop = wl1271_op_stop,
4506 .add_interface = wl1271_op_add_interface,
4507 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004508#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004509 .suspend = wl1271_op_suspend,
4510 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004511#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004512 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004513 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004514 .configure_filter = wl1271_op_configure_filter,
4515 .tx = wl1271_op_tx,
4516 .set_key = wl1271_op_set_key,
4517 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004518 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004519 .sched_scan_start = wl1271_op_sched_scan_start,
4520 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004521 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004522 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004523 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004524 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004525 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004526 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004527 .sta_add = wl1271_op_sta_add,
4528 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004529 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004530 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004531 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004532 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004533 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004534};
4535
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004536
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004537u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004538{
4539 u8 idx;
4540
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004541 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004542
4543 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4544 wl1271_error("Illegal RX rate from HW: %d", rate);
4545 return 0;
4546 }
4547
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004548 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004549 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4550 wl1271_error("Unsupported RX rate from HW: %d", rate);
4551 return 0;
4552 }
4553
4554 return idx;
4555}
4556
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004557static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4558 struct device_attribute *attr,
4559 char *buf)
4560{
4561 struct wl1271 *wl = dev_get_drvdata(dev);
4562 ssize_t len;
4563
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004564 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004565
4566 mutex_lock(&wl->mutex);
4567 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4568 wl->sg_enabled);
4569 mutex_unlock(&wl->mutex);
4570
4571 return len;
4572
4573}
4574
4575static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4576 struct device_attribute *attr,
4577 const char *buf, size_t count)
4578{
4579 struct wl1271 *wl = dev_get_drvdata(dev);
4580 unsigned long res;
4581 int ret;
4582
Luciano Coelho6277ed62011-04-01 17:49:54 +03004583 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004584 if (ret < 0) {
4585 wl1271_warning("incorrect value written to bt_coex_mode");
4586 return count;
4587 }
4588
4589 mutex_lock(&wl->mutex);
4590
4591 res = !!res;
4592
4593 if (res == wl->sg_enabled)
4594 goto out;
4595
4596 wl->sg_enabled = res;
4597
4598 if (wl->state == WL1271_STATE_OFF)
4599 goto out;
4600
Ido Yariva6208652011-03-01 15:14:41 +02004601 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004602 if (ret < 0)
4603 goto out;
4604
4605 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4606 wl1271_ps_elp_sleep(wl);
4607
4608 out:
4609 mutex_unlock(&wl->mutex);
4610 return count;
4611}
4612
4613static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4614 wl1271_sysfs_show_bt_coex_state,
4615 wl1271_sysfs_store_bt_coex_state);
4616
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004617static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4618 struct device_attribute *attr,
4619 char *buf)
4620{
4621 struct wl1271 *wl = dev_get_drvdata(dev);
4622 ssize_t len;
4623
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004624 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004625
4626 mutex_lock(&wl->mutex);
4627 if (wl->hw_pg_ver >= 0)
4628 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4629 else
4630 len = snprintf(buf, len, "n/a\n");
4631 mutex_unlock(&wl->mutex);
4632
4633 return len;
4634}
4635
Gery Kahn6f07b722011-07-18 14:21:49 +03004636static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004637 wl1271_sysfs_show_hw_pg_ver, NULL);
4638
Ido Yariv95dac04f2011-06-06 14:57:06 +03004639static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4640 struct bin_attribute *bin_attr,
4641 char *buffer, loff_t pos, size_t count)
4642{
4643 struct device *dev = container_of(kobj, struct device, kobj);
4644 struct wl1271 *wl = dev_get_drvdata(dev);
4645 ssize_t len;
4646 int ret;
4647
4648 ret = mutex_lock_interruptible(&wl->mutex);
4649 if (ret < 0)
4650 return -ERESTARTSYS;
4651
4652 /* Let only one thread read the log at a time, blocking others */
4653 while (wl->fwlog_size == 0) {
4654 DEFINE_WAIT(wait);
4655
4656 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4657 &wait,
4658 TASK_INTERRUPTIBLE);
4659
4660 if (wl->fwlog_size != 0) {
4661 finish_wait(&wl->fwlog_waitq, &wait);
4662 break;
4663 }
4664
4665 mutex_unlock(&wl->mutex);
4666
4667 schedule();
4668 finish_wait(&wl->fwlog_waitq, &wait);
4669
4670 if (signal_pending(current))
4671 return -ERESTARTSYS;
4672
4673 ret = mutex_lock_interruptible(&wl->mutex);
4674 if (ret < 0)
4675 return -ERESTARTSYS;
4676 }
4677
4678 /* Check if the fwlog is still valid */
4679 if (wl->fwlog_size < 0) {
4680 mutex_unlock(&wl->mutex);
4681 return 0;
4682 }
4683
4684 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4685 len = min(count, (size_t)wl->fwlog_size);
4686 wl->fwlog_size -= len;
4687 memcpy(buffer, wl->fwlog, len);
4688
4689 /* Make room for new messages */
4690 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4691
4692 mutex_unlock(&wl->mutex);
4693
4694 return len;
4695}
4696
4697static struct bin_attribute fwlog_attr = {
4698 .attr = {.name = "fwlog", .mode = S_IRUSR},
4699 .read = wl1271_sysfs_read_fwlog,
4700};
4701
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004702int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004703{
4704 int ret;
4705
4706 if (wl->mac80211_registered)
4707 return 0;
4708
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004709 ret = wl1271_fetch_nvs(wl);
4710 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004711 /* NOTE: The wl->nvs->nvs element must be first, in
4712 * order to simplify the casting, we assume it is at
4713 * the beginning of the wl->nvs structure.
4714 */
4715 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004716
4717 wl->mac_addr[0] = nvs_ptr[11];
4718 wl->mac_addr[1] = nvs_ptr[10];
4719 wl->mac_addr[2] = nvs_ptr[6];
4720 wl->mac_addr[3] = nvs_ptr[5];
4721 wl->mac_addr[4] = nvs_ptr[4];
4722 wl->mac_addr[5] = nvs_ptr[3];
4723 }
4724
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004725 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4726
4727 ret = ieee80211_register_hw(wl->hw);
4728 if (ret < 0) {
4729 wl1271_error("unable to register mac80211 hw: %d", ret);
4730 return ret;
4731 }
4732
4733 wl->mac80211_registered = true;
4734
Eliad Pellerd60080a2010-11-24 12:53:16 +02004735 wl1271_debugfs_init(wl);
4736
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004737 register_netdevice_notifier(&wl1271_dev_notifier);
4738
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004739 wl1271_notice("loaded");
4740
4741 return 0;
4742}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004743EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004744
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004745void wl1271_unregister_hw(struct wl1271 *wl)
4746{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004747 if (wl->state == WL1271_STATE_PLT)
4748 __wl1271_plt_stop(wl);
4749
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004750 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004751 ieee80211_unregister_hw(wl->hw);
4752 wl->mac80211_registered = false;
4753
4754}
4755EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4756
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004757int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004758{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004759 static const u32 cipher_suites[] = {
4760 WLAN_CIPHER_SUITE_WEP40,
4761 WLAN_CIPHER_SUITE_WEP104,
4762 WLAN_CIPHER_SUITE_TKIP,
4763 WLAN_CIPHER_SUITE_CCMP,
4764 WL1271_CIPHER_SUITE_GEM,
4765 };
4766
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004767 /* The tx descriptor buffer and the TKIP space. */
4768 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4769 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004770
4771 /* unit us */
4772 /* FIXME: find a proper value */
4773 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004774 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004775
4776 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004777 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004778 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004779 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004780 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004781 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004782 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004783 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004784 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03004785 IEEE80211_HW_AP_LINK_PS |
4786 IEEE80211_HW_AMPDU_AGGREGATION |
4787 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004788
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004789 wl->hw->wiphy->cipher_suites = cipher_suites;
4790 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4791
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004792 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03004793 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
4794 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004795 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03004796 wl->hw->wiphy->max_sched_scan_ssids = 16;
4797 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02004798 /*
4799 * Maximum length of elements in scanning probe request templates
4800 * should be the maximum length possible for a template, without
4801 * the IEEE80211 header of the template
4802 */
Eliad Peller154037d2011-08-14 13:17:12 +03004803 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004804 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004805
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03004806 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
4807 sizeof(struct ieee80211_header);
4808
Eliad Peller1ec23f72011-08-25 14:26:54 +03004809 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
4810
Luciano Coelho4a31c112011-03-21 23:16:14 +02004811 /* make sure all our channels fit in the scanned_ch bitmask */
4812 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4813 ARRAY_SIZE(wl1271_channels_5ghz) >
4814 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004815 /*
4816 * We keep local copies of the band structs because we need to
4817 * modify them on a per-device basis.
4818 */
4819 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4820 sizeof(wl1271_band_2ghz));
4821 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4822 sizeof(wl1271_band_5ghz));
4823
4824 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4825 &wl->bands[IEEE80211_BAND_2GHZ];
4826 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4827 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004828
Kalle Valo12bd8942010-03-18 12:26:33 +02004829 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004830 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004831
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004832 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4833
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004834 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004835
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004836 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02004837 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004838
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004839 wl->hw->max_rx_aggregation_subframes = 8;
4840
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004841 return 0;
4842}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004843EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004844
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004845#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004846
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004847struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004848{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004849 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004850 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004851 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004852 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004853 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004854
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004855 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03004856
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004857 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4858 if (!hw) {
4859 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004860 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004861 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004862 }
4863
Julia Lawall929ebd32010-05-15 23:16:39 +02004864 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004865 if (!plat_dev) {
4866 wl1271_error("could not allocate platform_device");
4867 ret = -ENOMEM;
4868 goto err_plat_alloc;
4869 }
4870
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004871 wl = hw->priv;
4872 memset(wl, 0, sizeof(*wl));
4873
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004874 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02004875 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004876
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004877 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004878 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004879
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004880 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004881 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004882 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4883
Ido Yariva6208652011-03-01 15:14:41 +02004884 skb_queue_head_init(&wl->deferred_rx_queue);
4885 skb_queue_head_init(&wl->deferred_tx_queue);
4886
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004887 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02004888 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004889 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4890 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4891 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004892 INIT_WORK(&wl->rx_streaming_enable_work,
4893 wl1271_rx_streaming_enable_work);
4894 INIT_WORK(&wl->rx_streaming_disable_work,
4895 wl1271_rx_streaming_disable_work);
4896
Eliad Peller92ef8962011-06-07 12:50:46 +03004897 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4898 if (!wl->freezable_wq) {
4899 ret = -ENOMEM;
4900 goto err_hw;
4901 }
4902
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004903 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004904 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004905 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004906 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004907 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004908 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004909 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004910 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004911 wl->ap_ps_map = 0;
4912 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004913 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004914 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004915 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004916 wl->tx_security_seq = 0;
4917 wl->tx_security_last_seq_lsb = 0;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03004918 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004919 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03004920 wl->active_sta_count = 0;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004921 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4922 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004923 wl->fwlog_size = 0;
4924 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004925
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004926 /* The system link is always allocated */
4927 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4928
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004929 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004930 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004931 wl->tx_frames[i] = NULL;
4932
4933 spin_lock_init(&wl->wl_lock);
4934
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004935 wl->state = WL1271_STATE_OFF;
4936 mutex_init(&wl->mutex);
4937
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004938 /* Apply default driver configuration. */
4939 wl1271_conf_init(wl);
4940
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004941 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4942 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4943 if (!wl->aggr_buf) {
4944 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004945 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004946 }
4947
Ido Yariv990f5de2011-03-31 10:06:59 +02004948 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4949 if (!wl->dummy_packet) {
4950 ret = -ENOMEM;
4951 goto err_aggr;
4952 }
4953
Ido Yariv95dac04f2011-06-06 14:57:06 +03004954 /* Allocate one page for the FW log */
4955 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4956 if (!wl->fwlog) {
4957 ret = -ENOMEM;
4958 goto err_dummy_packet;
4959 }
4960
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004961 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004962 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004963 if (ret) {
4964 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004965 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004966 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004967 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004968
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004969 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004970 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004971 if (ret < 0) {
4972 wl1271_error("failed to create sysfs file bt_coex_state");
4973 goto err_platform;
4974 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004975
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004976 /* Create sysfs file to get HW PG version */
4977 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4978 if (ret < 0) {
4979 wl1271_error("failed to create sysfs file hw_pg_ver");
4980 goto err_bt_coex_state;
4981 }
4982
Ido Yariv95dac04f2011-06-06 14:57:06 +03004983 /* Create sysfs file for the FW log */
4984 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4985 if (ret < 0) {
4986 wl1271_error("failed to create sysfs file fwlog");
4987 goto err_hw_pg_ver;
4988 }
4989
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004990 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004991
Ido Yariv95dac04f2011-06-06 14:57:06 +03004992err_hw_pg_ver:
4993 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4994
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004995err_bt_coex_state:
4996 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4997
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004998err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004999 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005000
Ido Yariv95dac04f2011-06-06 14:57:06 +03005001err_fwlog:
5002 free_page((unsigned long)wl->fwlog);
5003
Ido Yariv990f5de2011-03-31 10:06:59 +02005004err_dummy_packet:
5005 dev_kfree_skb(wl->dummy_packet);
5006
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005007err_aggr:
5008 free_pages((unsigned long)wl->aggr_buf, order);
5009
Eliad Peller92ef8962011-06-07 12:50:46 +03005010err_wq:
5011 destroy_workqueue(wl->freezable_wq);
5012
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005013err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005014 wl1271_debugfs_exit(wl);
5015 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005016
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005017err_plat_alloc:
5018 ieee80211_free_hw(hw);
5019
5020err_hw_alloc:
5021
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005022 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005023}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005024EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005025
5026int wl1271_free_hw(struct wl1271 *wl)
5027{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005028 /* Unblock any fwlog readers */
5029 mutex_lock(&wl->mutex);
5030 wl->fwlog_size = -1;
5031 wake_up_interruptible_all(&wl->fwlog_waitq);
5032 mutex_unlock(&wl->mutex);
5033
5034 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005035
5036 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
5037
5038 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005039 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005040 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005041 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005042 free_pages((unsigned long)wl->aggr_buf,
5043 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005044 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005045
5046 wl1271_debugfs_exit(wl);
5047
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005048 vfree(wl->fw);
5049 wl->fw = NULL;
5050 kfree(wl->nvs);
5051 wl->nvs = NULL;
5052
5053 kfree(wl->fw_status);
5054 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005055 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005056
5057 ieee80211_free_hw(wl->hw);
5058
5059 return 0;
5060}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005061EXPORT_SYMBOL_GPL(wl1271_free_hw);
5062
Guy Eilam491bbd62011-01-12 10:33:29 +01005063u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005064EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005065module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005066MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5067
Ido Yariv95dac04f2011-06-06 14:57:06 +03005068module_param_named(fwlog, fwlog_param, charp, 0);
5069MODULE_PARM_DESC(keymap,
5070 "FW logger options: continuous, ondemand, dbgpins or disable");
5071
Eliad Peller2a5bff02011-08-25 18:10:59 +03005072module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5073MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5074
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005075MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005076MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005077MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");